Giter Club home page Giter Club logo

font-end-interview-question's People

Contributors

sakila1012 avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

font-end-interview-question's Issues

如何用 css 或 js 实现多行文本溢出省略效果,考虑兼容性

1. 如何用 css 或 js 实现多行文本溢出省略效果,考虑兼容性

写法一

单行

width: 300px;
overflow: hidden;
text-overflow: ellip
white-space: nowrap;

多行

div{
  width: 300px;
  position: relative;
  line-height: 1.4em;
  height: 4.2em;
  overflow: hidden;
}
div::after{
  content: "...";
  position: absolute;
  right: 0;
  bottom: 0;
}

这种写法兼容性不行

写法二

<div id='box' style="width:400px; 
        height: 200px;
        line-height: 30px;
        border: 1px solid #666666;
        overflow:auto;"> </div>
<script>
    let str = '这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本是文本这是文本这是文本';
    let box = document.getElementById('box');
    H = box.offsetHeight;
    for(i=0; i<str.length; i++){
        box.innerHTML = str.substring(0,i);
        if(H<box.scrollHeight){
            box.style.overflow = 'hidden';
            box.innerHTML = str.substring(0,i-3) + '...';
            break;
        }
    }
</script>

写法三

p.line {
    overflow: hidden;
    -ms-text-overflow: ellipsis;
    text-overflow: ellipsis;
    display:-webkit-box; //将对象作为弹性伸缩盒子模型显示。
    -webkit-box-orient:vertical; //从上到下垂直排列子元素(设置伸缩盒子的子元素排列方式)
    -webkit-line-clamp: 2; // 显示行数,超出两行隐藏且多余的用省略号表示...
    line-clamp: 2;
    max-width: 210px; // 有必要定义max-width
}

写法四

$('.ellipsis').each(function(
    $('span', $(this)).css('word-break', 'break-all')
     var divH = $(this).height()
     var $span = $('span', $(this)).eq(0)
     while ($span.outerHeight() > divH) {
          $span.text($span.text().replace(/(\s)*([a-zA-Z0-9]+|\W)(\.\.\.)?$/, '...'))
     }
})

写法五

const p = document.querySelector('p')
let words = p.innerHTML.split(/(?<=[\u4e00-\u9fa5])|(?<=\w*?\b)/g)
while (p.scrollHeight > p.clientHeight) {
  words.pop()
  p.innerHTML = words.join('') + '...'
}

递归

实际应用场景
将数组obj格式:

var obj = [
    {id:1, parent: null},
    {id:2, parent: 1},
    {id:3, parent: 2},
];

转换为obj2格式:

var obj2 = {
    obj: {
        id: 1,
        parent: null,
        child: {
            id: 2,
            parent: 1,
            child: {
                id: 3,
                parent: 2
            }
        }
    }
}

代码实现

var obj2 = {};
function createObj2(obj, child){
    if(child.parent){
        if(obj.obj){
            createObj2(obj.obj, child);
        }else{
            if(obj.id === child.parent){
                obj.child = {
                    id: child.id,
                    parent: child.parent,
                }
            }else{
                if(obj.child){
                    createObj2(obj.child, child);
                }else{
                    console.log('obj2未匹配到对应的parent对应关系')
                }
            }
        }
    }else{
        obj.obj = {
            id: child.id,
            parent: child.parent,
            child: {}
        }
    }
}
obj.forEach((item, item_i) => {
    createObj2(obj2, item)
})
console.log('obj2:', obj2)

页面加载海量数据

10w 条记录的数组,一次性渲染到页面上,如何处理可以冻结 UI?

页面上有个空的无序列表节点 ul,其 idlist-width-big-data,现需要往列表插入 10w 个 li,每个列> 表项文本内容可自行定义,且要求当每个 li 被单击时,通过 alert 显示列表项内的文本内容。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta http-equiv="X-UA-Compatiable" content="ie=edge">
     <title>页面加载海量数据</title>
  </head>
  <body>
    <ul id="list-width-big-data">100000</ul>
    <script>
       //  此处添加你的代码逻辑
    </script>
  </body>
</html>

我们可以从 减少 DOM 操作次数缩短循环时间 两个方面减少主线程阻塞的时间。

在MDN中,通过 DocumentFragment 的使用,减少 DOM 操作次数,降低回流对性能的影响。

requestAniminationFrame

在缩短循环时间方面,我们可以通过 分治 的**,将 100000 个 li 分批插入到页面中,并且我们通过 requestAniminationFrame,在页面重绘前插入新节点。

事件绑定

如果想监听海量元素,推荐方法是使用 JavaScript 的事件机制,实现事件委托,这样可以显著减少 DOM 事件注册的数量。

解决方法

const ulContainer = document.getElementById("list-width-big-data");

// 防御性编程
if (!ulContainer) {
  return;
}

const total = 100000; // 插入数据的总数
const batchSize  = 4; // 每次批量插入的节点个数,个数越多,界面越卡顿
const batchCount = total / batchSize; // 批处理的次数

function appendItems() {
  // 使用 DocumentFragment 减少 DOM 操作次数,对已有元素不进行回流
  const fragment = document.createDocumentFragment();
  
  for (let i=0; i<batchSize; i++) {
    const liItem = document.createElement("li");
    liItem.innerText = batchDone * batchSize + i + 1;
    fragment.appendChild(liItem);
  }

  // 每次批处理只修改 1 次 DOM
  ulContainer.appendChild(fragment);
  batchDone ++;
  doApendBatch();
}

function doAppendBatch() {
  if (batchDone < batchCount) {
     // 在重绘之前,分批插入新节点
    window.requestAnimationFrame(appendItems);
   }
}

doAppendBatch();

// 使用 事件委托,利用 JavaScript 的事件机制,实现对海量元素的监听,有效减少事件注册的数量
ulContainer.addEventListener("click", function(e) {
  const target = e.target;
  
  if(target.tagName === "LI") {
    alert(target.innerText);
  }
});

跨域问题总结

  1. 跨域如何产生的
  2. 跨域的解决方法

浏览器安全的基石是“同源策略”(same-origin policy)。

一、介绍

1.1 含义

1995年,同源策略由 Netscape 公司引入浏览器。目前,所有的浏览器都支持这个政策。
最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页“同源”。同源指的是“三个相同”。

  • 协议相同
  • 域名相同
  • 端口相同

举例来说,http://www.example.com/dir/page.html这个网址,协议是 http://,域名是 www.example.com ,端口是 80(默认端口号可以省略)。它的同源情况如下。
* http://www.example.com/dir2/other.html:同源
* http://example.com/dir/other.html:不同源(域名不同)
* http://v2.www.example.com/dir/other.html:不同源(域名不同)
* http://www.example.com:81/dir/other.html:不同源(端口不同)

1.2 目的

同源策略的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样的一个情况:A网站是一家银行,用户登陆以后,又去浏览器其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄露。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。

由此可见,“同源策略”是必须的,否则 Cookie 可以共享,互联网就毫无安全可言了。

1.3 限制范围

随着互联网的发展,“同源策略”越来越严格了。目前,如果非同源,共有三种行为受到限制。

(1)  Cookie、LocalStorage 和 IndexDB 无法读取。
(2)  DOM 无法获得。
(3)  AJAX 请求不能发送

虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。下面,将详细介绍,如何规避上面三种限制。

##二 、Cookie
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置 document.domain 共享 Cookie.

举例来说,A网页是 http://w1.example.com/a.html,B网页是 http://w2.example.com/b.html,那么只要设置相同的 document.domain,两个网页就可以共享 Cookie。

document.domain = "example.com";

现在,A 网页通过脚本设置一个 Cookie。

document.cookie = "test1=hello";

B 网页就可以读到这个 Cookie。

var allCookie = document.cookie;

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源策略,而要使用下文介绍的 PostMessage API。

另外,服务器也可以设置 Cookie 的时候,指定 Cookie 的所有域名为一级域名,比如 .example.com

Set-Cookie: key=value;domain=.example.com.都可以读取这个 Cookie。

##三、iframe
如果两个网页不同源,就无法拿到对方的 DOM。典型的例子是 iframe 窗口和 window.open 方法打开的窗口,他们与父窗口无法通信。比如,父窗口运行下面的命令,如果 iframe 窗口不是同源,就会报错。

document.getElementById("myFrame").contentWindow.document

上面命令中,父窗口想获取子窗口的 DOM,因为跨源导致报错。
反之亦然,子窗口获取主窗口的 DOM 也会报错。

window.parent.document.body

如果两个窗口一级域名相同,只有二级域名不同,那么设置上一节介绍的 document.domain 属性,就可以规避同源策略,拿到 DOM。

对于完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。

片段识别符
window.name
跨文档通信 API(Cross-document messaging)

3.1 片段识别符
片段识别符(fragment indentifier)指的是,URL的 # 号后面的部分,比如 http://example.com/x.html#fragment 的 #fragment。
如果只是改变片段标识符,页面不会重新刷新。

父窗口可以把信息,写入子窗口的片段标识符。

var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

子窗口通过监听 hashchange 事件得到通知。

window.onhashchange = checkMessage;
function checkMessage() {
  var message = window.location.hash;
}

同样的,子窗口也可以改变父窗口的片段标识符。

parent.location.href = target + '#' + hash;

3.2 window.name

浏览器窗口有 window.name 属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页就可以读取它。

window.name = data;

接着,子窗口跳回一个与主窗口同域的网址。

location = 'http://parent.url.com/xxx.html';

然后,主窗口就可以读取子窗口的 window.name 了。

var data = document.getElementById('myFrame').contentWindow.name;

这种方法的优点是,window.name 容量很大,可以放置非常长的字符串;缺点是必须监听子窗口 window.name 属性的变化,影响网页性能。

3.3 window.postMessage

上面两种方法都属于破解,HTML5为了解决这个问题,引入一个全新的 API:跨文档通信 API(cross-document mesaging)。
这个 API 为 window 对象新增了一个 window.postMessage 方法,允许跨窗口通信,不论这两个窗口是否同源。
举例说,父窗口 http://aaa.com 向子窗口 http://bbb.com 发消息,调用 postMessage 方法就可以了。

var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage 方法的第一个参数是具体信息内容,第二个参数是接受消息的窗口的源,即“协议+域名+端口”。也可以设为 *,表示不限制域名,向所有窗口发送。

子窗口向父窗口发送消息的写法类似。

window.opener.postMessage('Nice to see you', 'http://aaa.com');

父窗口和子窗口都可以通过 message 事件,监听对方的消息。

window.addEventListener('message', function(e){
  console.log(e.data);
},false);

message 事件的事件对象 event,提供了以下三个属性。

event.source:  发送消息的窗口
event.origin:  消息发向的网址
event.data:  消息内容

下面的例子是: 子窗口通过 event.source 属性引用父窗口,然后发送消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postmessage('Nice to see you!', '*');
}

event.origin 属性可以过滤不是发送本窗口的消息。

window.addEventListener('message', receiveMessage);
function reeiveMessage(event) {
   if(event.origin !== 'http://aaa.com') return;
  if(event.data === 'Hello World') {
  event.source.postMessage('Hello', event.origin);
} else {
  console.log(event.data);
}
}

3.4 LocalStorage

通过 window.postMessage,读写其他窗口的 LocalStorage 也成为了可能。
下面是一个例子,主窗口写入 iframe 子窗口的 localstorage。

window.onmessage = function(e) {
  if(e.origin !== 'http://bbb.com') {
    return;
  }
  var payload = JSON.parse(e.data);
  localStorage.setItem(payload.key, JSON.stringify(payload.data));
}

上面代码中,子窗口将父窗口发来的信息,写入自己的 LocalStorage。
父窗口发送消息的代码如下。

var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = {name: 'Jack'};
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com');

加强版的子窗口接收消息的代码如下。

window.onmessage = function(e) {
  if(e.origin !== 'http://bbb.com') return;
  var payload = JSON.parse(e.data);
  switch (payload.method) {
    case 'set':
      localStorage.setItem(payload.key, JSON.stringify(payload.data));
      break;
    case: 'get':
      var parent = window.parent;
      var data = localStorage.getItem(payload.key);
      parent.postMessage(data, 'http://aaa.com');
      break;
    case: 'remove':
       localStorage.removeItem(payload.key);
       break;
  }
}

加强版的父窗口发送消息代码如下:

var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = {name: 'jack'};
//存入对象
win.postMesage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
//读取对象
window.onmessage = function(e) {
   if(e.origin != 'http://aaa.com') return;
   console.log(JSON.parse(e.data).name);
}

四、AJAX

同源策略规定,AJAX请求只能发送给同源的网址,否则就会报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。

JSONP
Websocket
CORS

4.1 JSONP

JSONP是服务器与客户端跨源通信的常用方法。最大的特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
它的基本**是,网页通过添加一个 <script>元素,向服务器请求 JSONP 数据,这种做法不受同源策略限制,服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入<script>元素,由它向跨源网址发出请求。

function addScript(src) {
  var script = document.createElement('script');
  script.setAttribute('type','text/javascript');
  script.src = src;
  document.body.appendChild(script);
}
window.onload = function() {
  addSciptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is : ' + data.ip);
}

上面代码通过动态添加<script>元素,向服务器 example.com 发出请求。注意,该请求的查询字符串有一个 callback 参数,用来指定回调函数的名字,这对于JSONP是必须的。
服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

foo({
  'ip' : '8.8.8.8'
})

由于 元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了 foo 函数,该函数就立即调用。作为参数的JSON数据视为JavaScript 对象,而不是字符串,因此避免使用 JSON.parse的步骤。

4.2 WebSocket

WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源策略,只要服务器支持,就可以通过它进行跨源通信。
下面是一个例子,浏览器发出的WebSocket 请求的头信息(摘自维基百科)

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面的代码中,有一个字段是 Origin,表示该请求的请求源(origin),即发自哪个域名。
正是因为有了 Origin 这个字段,所以 WebSocket 才没有实行同源策略。因为服务器可以根据这个字段,判断是否许可这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器会做出如下回应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

4.3 CORS

CORS 是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发 GET 请求,CORS允许任何类型的请求。

面试题

CSS

1、如何实现左侧高度随右侧高度变化(如何实现两栏等高布局)
以下是部分css样式
`

  • {margin:0;padding:0}
    .wrap {background:#ccc;overflow:hidden}
    .left {float: left; width: 200px;background: #ccc;padding-bottom:5000px;margin-bottom: -5000px;}
    .right {background: #f60;margin-left: 200px;word-break:break-all}
    `
    2、如何实现table动态切换

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.