vue3 大海賊時代發佈了,學習一下這一方面的知識,大佬,我我我我我,還學的動。個人肩膀寬,磚頭搬得動 vue
舉個簡單的例子webpack
const { reactive } = Vue
var App = {
template: `
<div>
{{message}}
</div>`,
setup() {
const state = reactive({message: "Hello World!!!"})
return {
...state
}
}
}
Vue.createApp().mount(App, '#app')
複製代碼
const { reactive } = Vue
let App = {
template: `
<div>
<input v-model="state.value"/>{{state.value}}
</div>`,
setup() {
const state = reactive({ value: '' })
return { state }
}
}
Vue.createApp().mount(App, '#app')
複製代碼
被詬病得地方,內容要寫在這個地方。setup 其實是一個組件的入口,它運行在組件被實例化時候,props 屬性被定義以後,實際上等價於 vue2 版本的 beforeCreate 和 Created 這兩個生命週期git
建立一個響應式得狀態,幾乎等價於 vue2.x 中的 Vue.observable() API,爲了不於 rxjs 中得 observable 混淆進行了重命名github
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0,
})
watchEffect(() => {
document.body.innerHTML = `count is ${state.count}`
})
return {...state}
複製代碼
watchEffect 和 2.x 中的 watch 選項相似,可是它不須要把被依賴的數據源和反作用回調分開。組合式 API 一樣提供了一個 watch 函數,其行爲和 2.x 的選項徹底一致。web
vue3 容許用戶建立單個的響應式對象api
const App = {
template: `
<div>
{{value}}
</div>`,
setup() {
const value = ref(0)
return { value }
}
}
Vue.createApp().mount(App, '#app')
複製代碼
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2),
})
function increment() {
state.count++
}
return {
state,
increment,
}
},
複製代碼
生命週期的變動數組
vue2 | vue3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
生命週期使用舉例:緩存
import { onMounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('component is mounted!')
})
},
}
複製代碼
vue3.0如何實現的 domdiff和vDOM的優化服務器
舉例:
<div id="app">
<p>週一呢</p>
<p>明天就週二了</p>
<div>{{week}}</div>
</div>
複製代碼
在vue2會被解析成一下代碼
function render() {
with(this) {
return _c('div', {
attrs: {
"id": "app"
}
}, [_c('p', [_v("週一呢")]), _c('p', [_v("明天就週二了")]), _c('div', [_v(
_s(week))])])
}
}
複製代碼
能夠看出,兩個p
標籤是徹底靜態的,以致於在後續的渲染中,其實沒有任何變化的,可是在vue2.x
中依然會使用_c
新建成一個vdom,在diff
的時候仍然須要去比較,這樣就形成了必定量的性能消耗
在vue3中
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("p", null, "週一呢"),
_createVNode("p", null, "明天就週二了"),
_createVNode("div", null, _toDisplayString(_ctx.week), 1 /* TEXT */)
]))
}
複製代碼
只有當_createVNode
的第四個參數不爲空的時候,這時,纔會被遍歷,而靜態節點就不會被遍歷到
同時發現了在vue3
最後一個非靜態的節點編譯後:出現了/* TEXT */
,這是爲了標記當前內容的類型以便進行diff
,若是不一樣的標記,只須要去比較對比相同的類型。這就不會去浪費時間對其餘類型進行遍歷了
export const enum PatchFlags {
TEXT = 1,// 表示具備動態textContent的元素
CLASS = 1 << 1, // 表示有動態Class的元素
STYLE = 1 << 2, // 表示動態樣式(靜態如style="color: red",也會提高至動態)
PROPS = 1 << 3, // 表示具備非類/樣式動態道具的元素。
FULL_PROPS = 1 << 4, // 表示帶有動態鍵的道具的元素,與上面三種相斥
HYDRATE_EVENTS = 1 << 5, // 表示帶有事件監聽器的元素
STABLE_FRAGMENT = 1 << 6, // 表示其子順序不變的片斷(沒懂)。
KEYED_FRAGMENT = 1 << 7, // 表示帶有鍵控或部分鍵控子元素的片斷。
UNKEYED_FRAGMENT = 1 << 8, // 表示帶有無key綁定的片斷
NEED_PATCH = 1 << 9, // 表示只須要非屬性補丁的元素,例如ref或hooks
DYNAMIC_SLOTS = 1 << 10, // 表示具備動態插槽的元素
}
複製代碼
若是存在兩種類型,那麼只須要對這兩個值對應的patchflag
進行位暈眩 如:TEXT
和PROPS
TEXT: 1 ,PROPRS: 1<<3 => 8
那麼對1和8進行按位與運算獲得=>9
複製代碼
2.事件儲存
綁定的事件會緩存在緩存中
<div id="app">
<button @click="handleClick">週五啦</button>
</div>
複製代碼
通過轉換=>
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = ($event, ...args) => (_ctx.handleClick($event, ...args)))
}, "週五啦")
]))
}
複製代碼
在代碼中能夠看出在綁定點擊事件的時候,會生成並緩存了一個內聯函數在cache中,變成了一個靜態的節點
<div id="app">
<p>週一了</p>
<p>週二了</p>
<div>{{week}}</div>
<div :class="{red:isRed}">週三呢</div>
</div>
複製代碼
轉換成=>
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
const _hoisted_1 = { id: "app" }
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "週一了", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "週二了", -1 /* HOISTED */)
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", _hoisted_1, [
_hoisted_2,
_hoisted_3,
_createVNode("div", null, _toDisplayString(_ctx.week), 1 /* TEXT */),
_createVNode("div", {
class: {red:_ctx.isRed}
}, "週三呢", 2 /* CLASS */)
]))
}
複製代碼
在這裏能夠看出來將一些靜態的節點放放在了render
函數的外部,這樣就避免了每次render
都會去生成一次靜態節點
vite 的使用,放棄原來vue2.x使用的 webpack
const {createSever} = require('vite')
vue2.x 使用的是defineProperty,有兩個難解決的問題
length
的方法而增長的長度沒法檢測到length的屬性被初始化成爲了
enumberable: false
configurable: false
writable: true
因此說直接去刪除或者修改length屬性是不行的
var a = [1,2,3]
Object.defineProperty(a,'length',{
enumberable: true,
configurable: true,
writable: true ,
})
=> Uncaught TypeError: Cannot redefine property: length
複製代碼
vue3 使用的是Proxy和Reflect,直接代理整個對象
function reactive(data) {
if (typeof data !== 'object' || data === null) {
return data
}
const observed = new Proxy(data, {
get(target, key, receiver) {
// Reflect有返回值不報錯
let result = Reflect.get(target, key, receiver)
// 多層代理
return typeof result !== 'object' ? result : reactive(result)
},
set(target, key, value, receiver) {
effective()
// proxy + reflect
const ret = Reflect.set(target, key, value, receiver)
return ret
},
deleteProperty(target,key){
const ret = Reflect.deleteProperty(target,key)
return ret
}
})
return observed
}
複製代碼
總結: