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

點擊穿透

參考文章

相關文章
相關標籤/搜索