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
}
复制代码
总结: