在下次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)
複製代碼