好好学习 天天向上

570 阅读7分钟

2020.03.24 vue - key的作用

问 : Vue项目时为什么要在列表组件中写 key,其作用是什么?

答 : Vue采用diff算法来对比新旧虚拟节点,key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度。

析 : 如果只是简单的列表渲染,没有key的情况下,不用去对比,就地复用,不需要销毁和创建所以基于这种情况下不带key的性能更好,但是实际开发中列表大部分都会带有很多状态所以还是推荐写key,比如一个带有选框的列表选中了第一条数据[麻辣香锅],如果没有key的情况下,在列表中使用unshift插入一条记录,则选中的就变成刚刚插入数据,如果有key无论如何插入数据选中的始终都是[麻辣香锅]。

带key效果

  • 不带key效果

不带key效果

<!--完整组件demo-->
<template>
  <div id="lists">
      <p @click="add">添加</p>
      <ul>
        <li v-for="(data,index) in listData" :key="data.id">
            <input type="checkbox"> {{data.title}}
        </li>
      </ul>
  </div>
</template>

<script>
export default {
  name: 'lists',
  data() {
    return {
      listData: [
        {id: 1,title: "麻辣香锅"},
        {id: 2,title: "油焖大虾"},
        {id: 3,title: "焦糖玛奇朵"},
        {id: 4,title: "黑糖玛奇朵"}
      ],
      addId:4
    };
  },
  methods: {
    add() {
      this.listData.unshift({id: ++this.addId,title: "黑糖玛奇朵黑糖玛奇朵"})
    }
  }
}
</script>

<style scoped style="scss">
ul {
  list-style-type: none;
  padding: 0;
}
li {
  margin: 10px;
}
</style>

2020.03.25 防抖和节流

问 : 防抖和节流?有什么区别?如何实现?

  1. 防抖

当持续触发事件时,一定时间段内没有触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发事件,就重新开始延时。常用的场景:input输入框

  • 思路

每次触发事件时都取消之前的延时调用方法

  1. 节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。常用的场景:页面滚动。

  • 思路

每次触发事件时都判断当前是否有等待执行的延时函数。有两种实现方式:时间戳 、 定时器。时间戳版本的第一次会立即执行,但是最后一次不会被执行。定时器版本的第一次不会执行,但是最后一次触发后会执行。

防抖

  • 节流

节流

//  防抖
function debounce(fn, awaits=500) {
  let timeout = null;
  return function() {
    clearTimeout(timeout)
    timeout = setTimeout(()=>{
      fn.call(this,arguments)
    },awaits)
  }
}

// 节流--定时器
function throttle(fn, awaits=500) {
  let canrun = true;
  return function() {
    if(!canrun){
      return;
    }
    canrun = false;
    setTimeout(() => {
      fn.call(this,arguments)
      canrun = true;
    }, awaits);
  }
}

// 节流--时间戳
function throttle1(fn, awaits=500) {
  let newdate = Date.now();
  return ()=>{
    let curdate = Date.now();
    if(curdate - newdate >= awaits){
      fn.call(this,arguments)
      newdate = Date.now();
    }
  }
}

// 节流--时间戳+定时器
function throttle2(fn, awaits=500) {
  let newdate = Date.now();
  let timeout = null;
  return ()=>{
    clearTimeout(timeout)
    let curdate = Date.now();
    if(curdate - newdate >= awaits){
      fn.call(this,arguments)
      newdate = Date.now();
    }else{
      timeout = setTimeout(() => {
        fn.call(this,arguments)
      }, awaits);
    }
  }
}
<!--完整组件demo-->
<template>
<div class="box">
  <input type="text" v-model="inputText" @input="inputFunction">
   <ul>
    <li></li>
    <li></li>
  </ul> 
</div>
</template>

<script>
// 防抖
function debounce(fn, awaits=500) {
  let timeout = null;
  return function() {
    clearTimeout(timeout)
    timeout = setTimeout(()=>{
      fn.call(this,arguments)
    },awaits)
  }
}

// 节流--定时器
function throttle(fn, awaits=500) {
  let canrun = true;
  return function() {
    if(!canrun){
      return;
    }
    canrun = false;
    setTimeout(() => {
      fn.call(this,arguments)
      canrun = true;
    }, awaits);
  }
}

// 节流--时间戳
function throttle1(fn, awaits=500) {
  let newdate = Date.now();
  return ()=>{
    let curdate = Date.now();
    if(curdate - newdate >= awaits){
      fn.call(this,arguments)
      newdate = Date.now();
    }
  }
}

// 节流--时间戳+定时器
function throttle2(fn, awaits=500) {
  let newdate = Date.now();
  let timeout = null;
  return ()=>{
    clearTimeout(timeout)
    let curdate = Date.now();
    if(curdate - newdate >= awaits){
      fn.call(this,arguments)
      newdate = Date.now();
    }else{
      timeout = setTimeout(() => {
        fn.call(this,arguments)
      }, awaits);
    }
  }
}

export default {
  name: 'debouncethrottle',
  data() {
    return {
      inputText:''
    };
  },
  methods: {
    test:function () {
      console.log(Math.random());
    },
    inputFunction:debounce(function(e){
      console.log(this.inputText)
    })
  },
  mounted() {
    let _this = this;
    window.addEventListener('scroll', throttle2(_this.test));
  }
}
</script>

<style>
ul li{
  display: block;
  width: 100px;
  height: 620px;
  margin-bottom: 20px;
  background: orange;;
}
</style>

2020.03.26 JS事件循环

基础概念 :

  • js是单线程的,同一个时间只能做一件事,虽然是单线程但是js有同步异步的概念解决了阻塞问题

  • 任务队列:同步任务在主线程依次执行,前一个结束才能执行后一个,异步任务则进入任务队列

  • 同步任务:一个函数返回的时候就可以拿到预期的结果,比如console.log()

  • 异步任务:函数返回的时候调用者不能拿到预期的结果,需要在将来的某一时刻才能拿到,比如ajax请求,异步任务分为宏任务、微任务

  • 宏任务(macro-task):script setTimeout, setInterval, setImmediate, I/O, UI rendering

  • 微任务(micro-task):process.nextTick, Promises, Object.observe, MutationObserver

  • promise的then和catch等 才是微任务,构造函数内的代码不是

  • 浏览器环境 node环境执行顺序不同

  • 任务队列遵循 ‘先入先出’

console.log('global')

for (var i = 1;i <= 5;i ++) {
  setTimeout(function() {
    console.log(i)
  },i*1000)
  console.log(i)
}

new Promise(function (resolve) {
  console.log('promise1')
  resolve()
 }).then(function () {
  console.log('then1')
})

setTimeout(function () {
  console.log('timeout2')
  new Promise(function (resolve) {
    console.log('timeout2_promise')
    resolve()
  }).then(function () {
    console.log('timeout2_then')
  })
}, 1000)

代码执行顺序分析

js事件循环

2020.03.30 js基础--原型链

  function Person(){

  }
  Person.prototype.name = 'Blues';

  let person = new Person();

  console.log('person.name');
  console.log(person.name);
  
  console.log('person.__proto__');
  console.log(person.__proto__);

  console.log('Person.prototype');
  console.log(Person.prototype);

  console.log('person.__proto__ === Person.prototype');
  console.log(person.__proto__ === Person.prototype);
  
  console.log('Person.prototype.__proto__');
  console.log(Person.prototype.__proto__);

  console.log('Object.prototype');
  console.log(Object.prototype);

  console.log('Person.prototype.__proto__ === Object.prototype')
  console.log(Person.prototype.__proto__ === Object.prototype)

原型链

原型链

今天发现的一篇挺不错的关于Vue的文章 -- Mark一下

高级前端开发者必会的34道Vue面试题系列

2020.04.01 浏览器渲染过程

问 : 输入url到展示页面过程中做了什么事情?

  1. DNS查询
  2. TCP连接
  3. HTTP请求响应
  4. 服务器响应
  5. 客户端(浏览器)渲染

1.DNS查询

(Domain Name System,域名系统)最初,由于ip长且难记,通过ip访问网站不方便。所以后来通过发明了DNS服务器,这个时候我们访问网站输入网站域名,DNS服务器就解析我们的域名为ip。这样我们实际访问的就是对应的ip地址啦。

抽象点DNS就是 一个记录ip地址的超级分布式数据库。

在浏览器中访问的时候,会优先访问浏览器缓存,如果访问指定域名,没有命中返回,则访问OS缓存。最后再次访问dns服务器。

(备注:就像每个人都有身份证号,但是人们相互联系通过身份证号标识-ip地址会很难记,通常我们都是记住一个人的名字-域名。)

2.TCP连接

TCP连接三次握手,四次挥手。为什么中间不能节省一次握手或者挥手,因为TCP连接是可靠的,要保证建立连接的基础上还要保证数据传输的完整性。

为什么TCP连接要三次握手,四次挥手

5.浏览器渲染分为几个步骤

  • 处理HTML并创建DOM树
  • 处理CSS并创建CSSOM树
  • 将DOM与CSSOM合并成一个渲染树
  • 根绝渲染树来布局,以计算每个节点的几何信息
  • 将各个节点绘制在屏幕上

浏览器的渲染:过程与原理

思考题1:36匹马 6个赛道 如何快速决出前三名

思考题2:100枚硬币 两个人 一次拿1-5枚 第一个人第一次拿多少 一定能拿到最后1枚硬币

2020.04.07 CORS CSRF XSS

  • CORS : Cross Origin Resourse-Sharing 跨站资源共享
  • CSRF : Cross-Site Request Forgery 跨站请求伪造
  • XSS : Cross Site Scrit 跨站脚本攻击(为与 CSS 区别,所以在安全领域叫 XSS)

CORS和CSRF




2020.04.09 js --- 打印机 总结(点击按钮实现打印以及打印分页)

问 : 如何实现分页

答 : 在想要分页的地方放上此代码就可以实现打印机的强制分页,但是实现过程中发现并不生效,查阅资料发现是由于 float 属性影响,移除 float 就可以了,或者按照项目实际情况使用 display:inline-block;来解决。

    //打印
    window.print();
    //分页
    <div style="page-break-after:always"></div>

2020.04.21 表单提交的常用几种方式

问 : 表单提交的常用几种方式?

答 :

// 方法1:type=submit方式提交
<form name="form" method="post" action="#"> 
    <input type="submit" name="submit" value="提交"> 
</form>
// 方法2:js提交
js    :  document.getElementById("form").submit();
jquery: $("#form").submit();
// 方法3:ajax提交
$.ajax({
      type: "POST",
      url: "/url.do",
      data: params,
      dataType : "json",
      success: function(respMsg){
      }
   });

阿里巴巴盒马前端上岸总结

form表单提交方式

2020.04.22 post和get的区别

问 : post和get的区别

答 :

  1. Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。
  2. Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制。
  3. Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
  4. Get执行效率却比Post方法好。Get是form提交的默认方法。

get-post区别

2020.04.23 响应式布局

问 : 响应式布局

  1. rem
  2. Grid 布局
  3. 媒体查询
(function(doc,win){
    var docEI = doc.documentElement,
    resizeEvt = 'orientationchange' in window?'orientataionchange':'resize',
    recalc = function(){
        var clientWidth = docEI.clientWidth;
        if(!clientWidth) return;
        docEI.style.fontSize = 100*(clientWidth/750)+'px';
    }

    if(!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document,window);

引用链接

2020.04.29 前后端常见的几种鉴权方式(前端鉴权)

  1. HTTP Basic Authentication
  2. session cookie
  3. Token
  4. OAuth

阮一峰 - OAuth 2.0 的一个简单解释

阮一峰 - OAuth 2.0 的四种方式

待更

2020.09.09 标题

问 : 问题

答 :

析 :

引用链接




js基础: ES6 、闭包 、 作用域问题 、 extends

网络相关: 从URL到页面显示的过程 、 http相关

安全相关: CSRF

其他:SSR