js笔记

Vue.nextTick(全局API)

在下次DOM更新循环结束以后执行延迟回调。在修改数据以后当即使用这个方法,获取更新后的DOMcss

// 修改数据
vm.msg = 'Hello';

// DOM 尚未更新
Vue.nextTick(function() {
    // DOM 更新了
})

// 做为Promise使用(2.1.0新增)
Vue.nextTick
    .then(function() {
        // DOM 更新了
    })

复制代码

vm.$nextTick (实例方法)

它跟全局方法Vue.nextTick同样,不一样的是回调的this自动绑定到调用它的实例上html

new Vue({
    methods: {
        example: function () {
            // 修改数据
            this.message = 'changed'
            // DOM 尚未更新
            this.$nextTick(function() {
                // DOM 如今更新了
                // this 绑定到当前的实例
                this.dosomething()
            })
        }
    }
    
})
复制代码

在下次更新DOM循环以后,这里比较重要的是vue中是异步更新队列前端

异步更新队列

Vue在更新DOM时是异步更新的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的全部数据变动。若是同一个watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时候去除重复数据对于避免没必要要的计算和DOM操做是很是重要的。而后,在下一个事件循环“tick”中,Vue刷新队列并执行实际(已去重复的)工做。vue

例如:当你设置vm.someData = 'new value', 该组件不会当即从新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。虽然Vue.js一般鼓励开发人员使用“数据驱动”的方式思考,避免直接接触DOM,可是有时咱们必须这么作。为了在数据变化以后等待Vue完成更新DOM,能够在数据变化以后当即使用Vue.nextTick(callback)。html5

在组件内使用vm.$nextTick()实例方法特别方便,由于不须要全局Vue,而且回调函数中的this将自动绑定到当前的Vue实例上:node

Vue.component('example', {
    template: '<span>{{ message }}</span>'
    data: function() {
        return {
            message: '未更新'
        }
    },
    methods: {
        updateMessage: function() {
            this.message = '已更新'
            console.log(this.$el.textContent)  // 未更新
            this.$nextTick(function() {
                console.log(this.$el.textContent) // 已更新
            })
        }
    }
})

复制代码

由于$nextTick返回一个promise对象,因此能够采用async/await来完成相同的事情es6

methods: {
    updateMessage: async function() {
        this.message = '已更新'
        console.log(this.$el.textContent) // 未更新
        await this.$nextTick()
        console.log(this.$el.textContent) // 已更新
    }
}

复制代码

computed 和 watch

计算属性(computed)是基于它们的响应式依赖进行缓存的。在大多数场景下更加合适。web

侦听属性(watch)是当须要在数据变化时执行异步或开销较大的操做时,这个方式是最有用的。算法

vue注意事项

1. vue不能检测如下的数组变更json

// 1. 利用索引值直接设置一个数组项, vm.items[2] = newValue
// 2. 当修改数组的长度时, vm.length = newLength

var vm = new Vue({
    data: {
        items: ['a', 'b', 'c']
    }
})

vm.items[1] = 'x'        // 1. 不是响应的
vm.items.length = 2     // 2. 不是响应的
复制代码

解决方法:

// 解决1问题
vm.$set(vm.items, indexOfItem, newValue)

// 解决2问题
vm.item.splice(newLength)
复制代码

2. vue不能检测对象属性的添加或则删除

var vm = new Vue({
    data: {
        a: 1
    }
})

// vm.a 是响应式的
vm.a = 2

// vm.b 不是响应式的
vm.b = 4

复制代码

对于已经建立的实例,Vue不容许动态添加根级别的响应式属性。

var vm = new Vue({
    data: {
        userProfile: {
            name: 'Anika'
        }
    }
})

vm.$set(vm.userProfile, 'age', 27)

// 添加多个响应式属性
vm.userProfile = Object.assign({}, vm.userProfile, {
    age: 27,
    color: 'vue Green'
})

复制代码

Scoped CSS

// scss 等预编译器

<style scoped lang="scss">
.a /deep/ .b {}

.a ::v-deep .b{}
</style>
复制代码

当使用Scss之类的预处理器,使用 /deep/或则::v-deep操做符代替 >>>

例:

// home父组件
<template>
    <div class="home">
        <yb-button></yb-button>
    </div>
</template>

<style lang="scss" scoped>
.home {
    ::v-deep button {
        color: red;
    }
}
</style>

// yb-button 子组件
<template>
    <div>
        <button>提交</button>
    <div>
</template>
复制代码

渲染出来的css样式:

.home[data-v-fae5bece] button {
    color: red;
}
复制代码

vue3.0 和vue2.0 在监听数据上的区别

1.vue2.0数据响应监听是使用Object.defineProperty的getter和setter方法;vue3.0将使用es6的proxy做为观察者机制;这将消除了Object.defineProperty所存在的局限性,没法对属性的增长检测,对数组变化检测。

node中间件作接口转发

当用户登陆成功返回不一样的几个角色,不一样的角色访问不一样的服务,nodejs写一个中间件而后经过正则判断进行分发。分发到不一样的服务接口。

MVVM

MVVM是Model-View-ViewModal的缩写,它是一种基于前端开发的架构模式,其核心是View和ViewModel的双向数据绑定,这使得ViewModel的状态改变可自动传递给View。

Vue.js是一个提供了MVVM风格的双向数据绑定的Javascript库,专一于View层。核心是MVVM中的VM,也就是ViewModel。ViewModel负责链接View和Model,保证视图和数据的一致性。

在vue中,mvvm表示

  1. m模型: 是指表明真实状态内容的领域模型,能够理解为表明内容的数据访问层(以数据为中心)
  2. v视图: 是指html中的结构,布局和外观(UI)
  3. vm视图模型: 暴露公共属性和命令的视图抽象,让视图和数据两者进行绑定通讯

移动端300ms点击延迟

由来:移动设备风靡以后,为了解决移动端适配的问题,提出来了viewport的解决方案,交互设计师为了更好的用户体验,特意提供了双击缩放的手势支持,这正是根源问题。移动浏览器会在touchend和click事件之间,等待300-350ms,判断用户是否会进行双击手势用以缩放文字。

解决方案:

  1. 禁用缩放
<meta name="viewport" content="user-scalable=no" />
复制代码

或则

html {
    touch-action: manipulation;
}

// IE on windows phone
html {
    touch-action: manipulation;         // IE11+
    -ms-touch-action: manipulation;     // IE10
}
复制代码
  1. 不由用缩放
<meta name="viewport" content="width=device-width"  />
复制代码
  1. fastClick

fastClick专门为300ms延迟问题开发出来的一个轻量级的库。 实现原理: 检测到touchend事件的时候,会经过DOM自定义事件当即触发模拟一个click事件,并把浏览器在300ms以后的click事件阻止掉。

参考连接:2019 再聊移动端 300ms 延迟及 fastClick 原理解析

一串用计算器输入的加减乘除用js实现计算结果

let str = "90+1-12+10*20-10/2+10-20";

    console.log(eval(str));         // 用于测试结果

    const codeArray = ['/', '+', '-', '*'];
    var signReg = /\/|\+|\-|\*/g;
    let tempNumArr = str.split(signReg);
    numArr = tempNumArr.map(x => {
      return parseInt(x)
    });
    let signArr = [];
    
    for (let i=0; i<str.length; i++) {
      if (signReg.test(str[i])) {
        signArr.push(str[i]);
      }
    }

    for (let y=0; y<signArr.length; y++) {
      if (signArr[y] === '/' || signArr[y] === '*') {
        switch (signArr[y]) {
          case '/':
            const result = numArr[y]/numArr[y+1];
            numArr.splice(y, 2, result);
            signArr.splice(y, 1);
            y=-1;
          break;
          case '*':
            const mulResult = numArr[y] * numArr[y+1];
            numArr.splice(y, 2, mulResult);
            signArr.splice(y, 1);
            y=-1;
          break;
        }
      }
    }

    for (let x=0; x<signArr.length; x++) {
      if (signArr[x] === '+' || signArr[x] === '-') {
        switch (signArr[x]) {
          case '+':
            const result = numArr[x] + numArr[x+1];
            numArr.splice(x, 2, result);
            signArr.splice(x, 1);
            x=-1;
          break;
          case '-':
            const miniResult = numArr[x] - numArr[x+1];
            numArr.splice(x, 2, miniResult);
            signArr.splice(x, 1);
            x=-1;
          break;
        }
      }
    }

    let [ completeNum ] = numArr;
    console.log(completeNum);

复制代码

html中拖拽功能初体验

// html
<div class="container">
  <div class="kanban-list-wrap">
    <div class="kanban-title">产品计划</div>
    <div class="kanban-bucket">
      <div class="kanban-card" draggable="true">
        <div class="task-priority"></div>
        <div class="task-content">保险表结构</div>
      </div>
    </div>
  </div>
  <div class="kanban-list-wrap">
    <div class="kanban-title">正在设计</div>
    <div class="kanban-bucket">
      <div class="kanban-card" draggable="true">
        <div class="task-priority"></div>
        <div class="task-content">保险原型设计</div>
      </div>
    </div>
  </div>
</div>

// css
* {
  padding: 0;
  margin: 0;
}
.container {
  height: 100vh;
  font-size: 14px;
  display: flex;
  background-color: #FAFAFA;
}
.kanban-list-wrap {
  width: 296px;
  margin-left: 24px;
}
.kanban-title {
  line-height: 48px;
  font-weight: 700;
  white-space: nowrap;
}
.kanban-bucket {
  position: relative;
  height: calc(100vh - 48px);
}
.kanban-card {
  position: relative;
  padding: 8px;
  border-radius: 5px;
  cursor: pointer;
  background-color: #fff;
  margin-top: 10px;
}
.task-priority {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 4px;
  border-bottom-left-radius: 5px;
  border-top-left-radius: 5px;
  transition: all 218ms ease-in;
  background-color: #ccc;
  opacity: 0;
}
.task-content {
  padding-left: 40px;
}
.kanban-card:hover .task-priority {
  opacity: 1;
}
.kanban-bucket-mask {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  padding-top: 20px;
  border-radius: 4px;
  border: 1px solid #0011aa;
  background-color: #fff;
  text-align: center;
}

// js
window.onload = function() {

  var dragged;

  document.addEventListener('drag', function(event) {

  }, false);

  document.addEventListener('dragstart', function(event) {
    if (event.target.className === 'kanban-card') {
      dragged = event.target;
      dragged.style.opacity = .5;
    }
    return false;
  }, false);

  document.addEventListener('dragend', function(event) {
    event.target.style.opacity = '';
  }, false);

  document.addEventListener('dragenter', function(event) {
    let target = event.target;
    if (target.className === 'kanban-bucket' && !target.contains(dragged)) {
      creatDIV('kanban-bucket-mask', target);
    }
  }, false);

  document.addEventListener('drop', function(event) {
    event.preventDefault();
    let target = event.target;
    if (target.className === 'kanban-bucket-mask') {
      target.parentNode.appendChild(dragged);
      target.parentNode.removeChild(target);
    }
  }, false);

  document.addEventListener('dragover', function(event) {
    event.preventDefault();
  }, false);

  function creatDIV(className, parentNode) {
    let div = document.createElement('div');
    div.className = className;
    div.textContent = '请拖拽至此';
    parentNode.appendChild(div);
  }

}

复制代码

注: 测试版本,google支持,IE11支持,firefox未支持

冒泡排序

// 两两比较,每一轮对比获取最大值放到数组最后
function bubbleSort(list) {
    for (let x=0; x<list.length; x++) {
        for (let y=0; y<list.length-x; y++) {
            if (list[y] > list[y+1]) {
                [list[y], list[y+1]] = [list[y+1], list[y]]
            }
        }
    }
}

复制代码

快速排序

// 1. 数组拆分三部分
// 2. 递归处理left
// 3. 递归处理right
// 4. 合并处理后的 结果
function quickSort(array) {
  if (array.length < 2) return array
  let pivot = array[array.length - 1]
  let left = array.filter((v, i) => v <= pivot && i != array.length -1)
  let right = array.filter(v => v > pivot)
  return [...quickSort(left), pivot, ...quickSort(right)]
}
复制代码

手写算法并记住它:快速排序(5行代码简单版)

for循环每隔1秒输出一个数

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

复制代码

写一个函数,对一个已经排好序的数组,若是当中两个数的和为指定target,返回true,不然返回false,时间复杂度O(n)

// 时间复杂度暂时不是很明白
function isTarget(arr, target) {
    for(let x=0; x<arr.length; x++) {
        for (let y=0; y<arr.length-y; y++) {
            if(arr[x] + arr[y] === target) {
                return true
            }
        }
    }
    return false
}
复制代码

promise, async, setTimeout最后执行结果

setTimeout(function() {
    console.log(1);
}, 100);

setTimeout(function() {
    console.log(2);
}, 0);

Promise.resolve(
    console.log(3);
).then(() => {
    console.log(4);
});

async function async1() {
    console.log(5)
    await async2()
    console.log(6)
}

async function async2() {
    console.log(7)
}

async1();
console.log(8);

//输出结果 3, 5, 7, 8, 4, 6, 2, 1
复制代码

打乱数组顺序

var orders = [1, 10, 9, 17, 28, 40];

function sortRandom() {
    return Math.random() > 0.5 ? 1 : -1;
}

orders.sort(sortRandom);
复制代码

es6中箭头函数

  1. 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
function print() {
    setTimeout(() => {
        console.log(this.id);
    }, 100)
}

var id = 20;
print.call({ id: 40 }); // 箭头函数定义时所在的对象

// 40  
/*
    setTimeout的参数是一个箭头函数
    若是是普通函数,执行时this应该指向全局对象window,应该输出20
    可是箭头函数致使this老是指向函数定义生效时所在的对象,输出40
*/


复制代码
  1. 不能够看成构造函数,也就是说不可使用new命令,不然会抛出一个错误
  2. 不可使用arguments,改对象在函数体内不存在。可使用rest参数代替
  3. 箭头函数使得this从“动态”变成“静态”

html5和html的区别

  1. html5是最新的第五代html标准。加强了对建立一个可以与用户进行交互的web应用的支持,使得与服务器交互比之前更加容易有效。
  2. html的doctype声明文件很是简单:
<!doctype>
复制代码
  1. 新增了新的元素属性,更加语义化的元素,header, footer,main等等
  2. 连通性,增长了web socket容许页面和服务器简历久链接并经过这种方法来交换非html数据,好比json数据
  3. 多媒体元素,使用html音视频,audio和video元素嵌入并支持新的多媒体内容操做
  4. 图像和效果的加强,canvas和svg的加入更加容易绘制出须要的图像
  5. 设备访问,容许使用和操做计算机的摄像头等等

建立和触发events

建立和分派DOM事件, 这些事件称为合成事件,而不是浏览器自己触发的事件。

// html
<div id="elem"></div>

// script
var elem = document.querySelector('#elem');
var event = document.creatEvent('Event');

// 用来初始化由Document.createEvent()建立的event实例
event.init('build', true, false);   // 能够冒泡,没法被取消

// 监听build事件
elem.addEventListener('build', function(e) {
    console.log(e.target); // 监听事件的目标元素
}, false)

复制代码

symbol是如何实现独一无二的数据

ES5的对象属性名都是字符串,容易形成属性名的冲突。 若是有一种机制,保证每一个属性的名字都是独一无二的就行了,能够从根本上防止属性名冲突。

注释: Symbol值不是对象,因此不能添加属性,它是一种相似于字符串的数据类型

对象的属性名如今能够有两种类型:

  1. 原来就有的字符串
  2. 新增的Symbol类型,
let s = Symbol();

typeof s
// 'symbol'


let s1 = Symbol('foo');

s1
// Symbol(foo)
复制代码

点击穿透

参考文章

相关文章
相关标签/搜索