Vue3学习记录(一)


vue3项目创建

可以使用Vite快速创建vue3项目

安装:npm install -g create-vite-app

创建项目:create-vite-app projectName

Vue2和Vue3的比较

diff比较

Vue2的diff是全局比较

image-20220217090229276

Vue3的diff是谁有标记就比较谁

image-20220217090524498

vue3新增了静态标记(PatchFlag),每次比较的时候只会比较带有patch flag的节点,并且通过pacth flag的类型得知要比较的内容。

// pacth flag 值与类型的对应关系
export const enum PatchFlags {
  TEXT = 1,// 动态文本节点
  CLASS = 1 << 1, // 2  // 动态 class
  STYLE = 1 << 2, // 4 // 动态 style
  PROPS = 1 << 3, // 8 // 动态属性,但不包含类名和样式
  FULL_PROPS = 1 << 4, // 16 // 具有动态 key 属性,当 key 改变时,需要进行完整的 diff 比较。
  HYDRATE_EVENTS = 1 << 5, // 32 // 带有监听事件的节点
  STABLE_FRAGMENT = 1 << 6, // 64 // 一个不会改变子节点顺序的 fragment
  KEYED_FRAGMENT = 1 << 7, // 128 // 带有 key 属性的 fragment 或部分子字节有 key
  UNKEYED_FRAGMENT = 1 << 8, // 256 // 子节点没有 key 的 fragment
  NEED_PATCH = 1 << 9, // 512 // 一个节点只会进行非 props 比较
  DYNAMIC_SLOTS = 1 << 10, // 1024 // 动态 slot
  HOISTED = -1, // 静态节点
  // 指示在 diff 过程应该要退出优化模式
  BAIL = -2
}

静态提升

Vue2中无论元素是否参与更新,每次都会重新创建,然后再次渲染。

Vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可。

    
哎哟喂

静态文本

{{msg}}

const _hoisted_1 = /*#__PURE__*/_createElementVNode("a", null, "哎哟喂 ", -1 /* HOISTED */) const _hoisted_2 = /*#__PURE__*/_createElementVNode("p", null, "静态文本", -1 /* HOISTED */) export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("div", null, [ _hoisted_1, _hoisted_2, _createElementVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */) ])) }

事件侦听器缓存

默认情况下(不使用cacheHandlers)onClick会被视为动态绑定,所以每次都会去追踪它的变化。

但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可。

事件监听缓存
开启事件监听缓存之前: const _hoisted_1 = ["onClick"] export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("div", null, [ _createElementVNode("button", { onClick: _ctx.Pooo }, "按钮", 8 /* PROPS */, _hoisted_1) ])) } 开启事件监听缓存之后: export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("div", null, [ _createElementVNode("button", { onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.Pooo && _ctx.Pooo(...args))) }, "按钮") ])) }

渲染和挂载

计算器:{{count}}

组合API

vue3提出了组合式API,并且提出了可以使用组合式API的地方——setup.






setup

setup函数执行时机位于beforeCreatecreated之前,所以setup函数中是无法使用datamethods,并且由于此时尚未创建组件实例,所以setup中并没有this

setup函数只能是同步的不能是异步的。

async setup(){} ×

reactive

reactive是vue3中提供的实现响应式数据的方法。在Vue2中响应式数据是通过defineProperty实现的。

Object.defineProperty(obj,'要监听的属性名',{set(newVal){},get(){}})

缺点:①不能监听数组的变化

? ②必须遍历对象的每个属性

? ③必须遍历深层次的对象

在Vue3中响应式数据是通过es6中的proxy对象实现的

let proxy = new Proxy(obj,handler)

优点

①无需一层层递归为每个属性添加代理

②可以完美监听到任何方式的数据改变

reactive参数必须是对象(json/arr)

如果给reactive传递了其他对象:

  • 默认情况下修改对象,界面不会自动更新

  • 如果想更新,可以通过重新赋值的方式

let state = reactive({
    time:new Date()
})
function myFn(){
    //state.time.setDate(state.time.getDate()+1) 数据变了,视图没有变
    const newtime = new Date(state.time.getTime())
    newtime.setDate(state.time.getDate()+1)
    state.time = newtime
}

ref

ref适合对简单类型数据的监听。ref低层的本质还是reactive,系统会自动转换成ref(xx)=>reactive({value:xx})

注意点:

①在Vue中使用ref的值不需要通过value获取

②在js中使用ref的值需要通过value获取

setup(){
    let count = ref(123);    // 这里会转为{value: 123}

    function handleClick(){
      count.value++;
      console.log(count.value); // 124 
    }

    return { count, handleClick }
  }

vue是如何判断当前的数据是否是ref类型的,通过当前数据的__v_isRef私有属性来判断的,Vue3提供了isRefisReactive判断类型。

vue