在下次DOM更新循环结束以后执行延迟回调。在修改数据以后当即使用这个方法,获取更新后的DOMcss
// 修改数据
vm.msg = 'Hello';
// DOM 尚未更新
Vue.nextTick(function() {
// DOM 更新了
})
// 做为Promise使用(2.1.0新增)
Vue.nextTick
.then(function() {
// DOM 更新了
})
复制代码
它跟全局方法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)是基于它们的响应式依赖进行缓存的。在大多数场景下更加合适。web
侦听属性(watch)是当须要在数据变化时执行异步或开销较大的操做时,这个方式是最有用的。算法
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'
})
复制代码
当
// 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;
}
复制代码
1.vue2.0数据响应监听是使用Object.defineProperty的getter和setter方法;vue3.0将使用es6的proxy做为观察者机制;这将消除了Object.defineProperty所存在的局限性,没法对属性的增长检测,对数组变化检测。
当用户登陆成功返回不一样的几个角色,不一样的角色访问不一样的服务,nodejs写一个中间件而后经过正则判断进行分发。分发到不一样的服务接口。
MVVM是Model-View-ViewModal的缩写,它是一种基于前端开发的架构模式,其核心是View和ViewModel的双向数据绑定,这使得ViewModel的状态改变可自动传递给View。
Vue.js是一个提供了MVVM风格的双向数据绑定的Javascript库,专一于View层。核心是MVVM中的VM,也就是ViewModel。ViewModel负责链接View和Model,保证视图和数据的一致性。
在vue中,mvvm表示
由来:移动设备风靡以后,为了解决移动端适配的问题,提出来了viewport的解决方案,交互设计师为了更好的用户体验,特意提供了双击缩放的手势支持,这正是根源问题。移动浏览器会在touchend和click事件之间,等待300-350ms,判断用户是否会进行双击手势用以缩放文字。
解决方案:
<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
}
复制代码
<meta name="viewport" content="width=device-width" />
复制代码
fastClick专门为300ms延迟问题开发出来的一个轻量级的库。 实现原理: 检测到touchend事件的时候,会经过DOM自定义事件当即触发模拟一个click事件,并把浏览器在300ms以后的click事件阻止掉。
参考连接:2019 再聊移动端 300ms 延迟及 fastClick 原理解析
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
<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)]
}
复制代码
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(() => {
console.log(i);
}, i * 1000)
})(i)
}
复制代码
// 时间复杂度暂时不是很明白
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
}
复制代码
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);
复制代码
function print() {
setTimeout(() => {
console.log(this.id);
}, 100)
}
var id = 20;
print.call({ id: 40 }); // 箭头函数定义时所在的对象
// 40
/*
setTimeout的参数是一个箭头函数
若是是普通函数,执行时this应该指向全局对象window,应该输出20
可是箭头函数致使this老是指向函数定义生效时所在的对象,输出40
*/
复制代码
<!doctype>
复制代码
建立和分派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)
复制代码
ES5的对象属性名都是字符串,容易形成属性名的冲突。 若是有一种机制,保证每一个属性的名字都是独一无二的就行了,能够从根本上防止属性名冲突。
注释: Symbol值不是对象,因此不能添加属性,它是一种相似于字符串的数据类型
对象的属性名如今能够有两种类型:
let s = Symbol();
typeof s
// 'symbol'
let s1 = Symbol('foo');
s1
// Symbol(foo)
复制代码