mozilla为我们提供了一个基于html5的pdf插件pdf.js。通过这个插件,可以在网页上直接打开pdf文本,不需要本地支持。Firefox浏览器就是用的这个插件。

pdf.js在github上的地址为https://github.com/mozilla/pdf.js

在github上的源码并不能直接使用,需要先进行构建。
首先打开git,clone到本地:

1
2
$ git clone git://github.com/mozilla/pdf.js.git
$ cd pdf.js

然后安装需要支持的包:

1
$ npm install

最后启动本地文本服务器:

1
$ node make server

然我们打开http://localhost:8888/web/viewer.html,可以看到:

可以从构建的文件中提取pdf.js的包,下面是我提取的一个包:

百度云

其中包含两个文件夹buildweb。在web文件夹内有一个viewer.html的html文件,这个文件主要负责pdf阅读器的结构样式,还有一个js文件viewer.js用于配置参数。在viewer.js中一个DEFAULT_URL常量,用于设置缺省的打开的pdf值。原文件中的默认值为compressed.tracemonkey-pldi-09.pdf。我们也可以通过地址栏参数传递参数来设置要代开的pdf文件,如…/web/viewer.html?file=12.pdf。参数file就是要打开文件的地址。在实际使用中可以通过在html文档中嵌入<iframe>标签实现,通过file来传递参数,如下:

1
<iframe src="js/pdfJS/web/viewer.html?file=public/嵌入式系统课程教学大纲.pdf" frameborder="0" width="100%" height="500"></iframe>

这是面试时遇到的一道题,与大家分享。

题目是这样的:

提供一个借口`dictionary(str)`:这个借口可以判断`str`是否为一个单词,如果是一个单词这返回`true`,否则返回`false`。
现在需要借助这个借口写一个函数`f(longStr)`:判断这个`longStr`是否可以被完整地分割成单词,即`longStr`由`dictionary(str)`判断为`true`的单词组成,且最后没有多余的字符。

下面给出我的思路:

我们可以递归调用这个函数`f`,如果第`longStr`的`n`个字符被`dictionary()`判断为单词,则用`longStr`的剩余字符串调用接口`dictionary()`,直到剩余的字符串长度为0,其中`n`从1开始递增。

给出我的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function f ( longStr) {
var n = 1;
var flag = false;
while ( ! flag && n < longStr.length ){
if ( dictionary ( longStr.substring(0,n) )) {
// 如果前n个字符是个单词则递归调用函数f
flag = f( substring(n) );
}else {
// 否则n自增
n++;
}
}
if ( flag || dictionary( longStr.substring(0,n) ) {
// dictionary ( longStr.substring(0,n) 判断整个longStr是否是个单词
return true;
} else {
return false;
}
}

这是一道百度校招的面试题

有由abcdefghijkl组成的字符串(不重复出现),求字符串按字母排列的位次:

如输入

1
"hgebkflacdji"

则输出为:

1
302715242

如输入

1
"abcdefghijlk"

则输出为:

1
2

我的求解方法:
思路:求字符串的第一个字母在数组temp中的位置(indexOf()求得)第一个位置确定后,后面的11位字符串可以由11!中排法,所以第一个字母为b则结果result加111!,并将其从数组中移除。然后继续第二个位置,求第二个位置的字母在temp数组中的位置(index),result加上index10!。。。依次类推到最后一个字符。最后的结果还要加上1。JavaScript程序如下:

1
var line = "hgebkflacdji";

var arr = line.split('');
result = 0;
var temp = 'abcdefghijkl'.split("");

// step内存放的是阶乘,分别是11!、10!...1!、0!
var step = [39916800, 3628800, 362880, 40320,5040,720, 120,24,6,2,1,1];
for ( var i = 0; i < arr.length; i++ ) {
	var a = arr[i];
	var index = temp.indexOf(a);
	result += index * step[i];
	temp.splice(index,1);
}
result = result+1;
console.log(result);

可惜在笔试时参考数值中字母顺序弄错了,就差一点,估计过不了百度的笔试了。

element.dataset能够获取元素的自定义属性,但是低版本的ie不支持,如何在低版本的ie上兼容类似的功能。
下面是我写的一个兼容IE的方法:

html

1
<div id="qwe" data-my="123"></div>

javascript

1
<div id="qwe" data-my="123"></div>

  function getDataSet(elem){
    if(elem.dataset){
      return elem.dataset;
    }
    var datas = {};
    var attrs = elem.attributes;
    var nodeName,nodeNames;
    for(var i = 0,attr;attr = attrs[i];i++){
      nodeName = attr.nodeName;
      if(nodeName.indexOf('data-')!==-1){
        nodeNames = nodeName.slice(5).split("-");
        nodeName = nodeNames[0];
      } else{
        continue;
      }
      for(var j=1;j<nodeNames.length;j++){
        nodeName += nodeNames[j].slice(0,1).toUpperCase + nodeNames[j].slice(1);
      }
      datas[nodeName] = attr.nodeValue;
      return datas;
    }
  }
  document.write(getDataSet(document.getElementById("qwe")).my);
  // 输出:123

这两天做了网易微前端的大作业,中间遇到了很多问题,通过解决这些问题学到了不少东西向。把在完成大作业过程中的问题记录下来以便日后温故。

css实现垂直水平居中

作业要求兼容IE8,一开始用的方法是:

1
2
3
4
5
6
7
.parent{position: relative;} 
.child{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}

但是这个方法只有IE9及以上版本浏览器支持。所以有经过一番寻找终于找到了解决方案:

1
2
3
4
5
6
7
8
// 支持IE7+
.parent{position: relative;}
.child{
position: absolute;
top: 50%;
left: 50%;
margin-left:-199px; margin-top:-139px;
}

IE8兼容背景透明

现代高级流量器已经兼容了css的rgba属性,但是这个属性在IE8中不支持。IE的低版本支持一个特殊的属性,即filter。一开始使用这个filter属性时有个问题,就是背景是透明了,但是背景内的内容也透明了。代码如下面:

1
2
3
.back{
filter:Alpha(opacity=80); background:#000;
}

经过在网上搜索发现了一个解决方案,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//css
.back {
background:rgba(255, 255, 255, 0.6)!important;
filter:Alpha(opacity=60); background:#fff; /* 使用IE专属滤镜实现IE背景透明*/
}
.back content{
position:relative; /*实现IE内容不透明*/
}

//html结构:
<div>
<div class="back">
<div class="content"></div>
</div>
</div>

经过仔细琢磨,发现只要是.back内的内容添加poistion属性就可以是其不再透明。

IE8浏览器的DOM兼容

IE8并不兼容W3C的标准事件模型,且没有实现document.getElementsByClassName()函数。
下面是一个兼容IE的事件注册和删除代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//事件注册
function addEvent(element, type, listener){
if (!!element.addEventListener){
element.addEventListener(type, listener, false);
}else if (element.attachEvent){
element.attachEvent('on'+type, listener);
}
}
//事件删除
function removeEvent(element, type, listener){
if (!!element.removeEventListener){
element.removeEventListener(type, listener, false);
}else if (element.detachEvent){
element.detachEvent('on'+type, listener);
}
}

下面是一个兼容IE的getElementsByClassName()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 兼容IE的类选择器getElementsByClassName
*
* @param {string} className 类名称
* @return {Array.<HTMLElement>} 返回匹配的元素列表
*/
function getElementsByClassName(className,context){
var context = context || document;
var result = [];
if(context.getElementsByClassName){
result = context.getElementsByClassName(className);
}else{
var temp = context.getElementsByTagName("*");
for(var i = 0, len = temp.length; i < len; i++){
var node = temp[i];
if(hasClass(node, className)){
result.push(node);
}
}
}
return result;
}

function hasClass(element, className){
var classNames = element.className;
if (!classNames) {
return false;
}
classNames = classNames.split(/\s+/);
for (var i = 0, len = classNames.length; i < len; i++) {
if (classNames[i] === className) {
return true;
}
}
return false;
}

另外还需要用到cookie,所以在完成作业过程中封装了处理cookie的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function setCookie (name, value, expires, path, domain, secure) {
var cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
if (expires){
cookie += ';expires='+expires.toGMTString();
}
if (path){
cookie += ';path='+path;
}
if (domain){
cookie += ';domain='+domain;
}
if (secure){
cookie += ';secure='+secure;
}
document.cookie = cookie;
}

function getCookie(){
var cookie = {};
var all = document.cookie;
if (all === ''){
return cookie;
}
var list = all.split("; ");
for (var i = 0; i < list.length; i++){
var item = list[i];
var p = item.indexOf('=');
var name = item.substring(0,p);
name = decodeURIComponent(name);
var value = item.substring(p+1);
value = decodeURIComponent(value);
cookie[name] = value;
}
return cookie;
}

function removeCookie(name, path, domain) {
document.cookie = name + '='
+ '; path=' + path
+ '; domian=' + domain
+ '; max-age=0';
}

IE8不支持element.previousElementSibling属性,所以也封装了一个previousElementSibling( el )方法:

1
2
3
4
5
6
7
8
9
function previousElementSibling( el ) {
if( el.previousElementSibling ) {
return el.previousElementSibling;
} else {
while( el = el.previousSibling ) {
if( el.nodeType === 1 ) return el;
}
}
}

未能解决的问题。

IE8中由于浏览器限制不能实现Ajax的跨域访问,所以不能在本地访问作业中提供的API接口。解决跨域问题可通过JSONP或者可以使用Frame代理、Web Socket等技术。不过在现代浏览器中已经实现了CORS(Cross-Origin Resource Sharing)的支持,可以实现跨域的资源访问。所以这里没有深入去了解这些技术。

我的作业