浅谈vue3 - 1

v2、v3双向绑定区别

  • v2

核心

  • 对象: 通过 defineProperty劫持对象已有的值的读取和修改
  • 数组: 通过重写数组更新数据一系列更新元素的方法实现元素修改的劫持

问题

  • 对象直接添加新的属性或删除已有的属性,页面不会自动更新
  • 直接通过下标替换元素或改变length,页面不会自动更新 arr[1] = {}
  Object.defineProperty(data,'元素',{
    get(){},
    set(){}
  })
  • v3

核心

  • 通过Proxy(代理): 拦截对data的任意(13种)操作,包括属性的读写,添加,删除等
  • 通过Reflect(反射): 动态对被代理对象的相应属性进行特定操作
  • 文档
new Proxy(data, {
  get(target, prop) { // 对象本身 get的属性
    console.log(starget, prop, 'get');
    return Reflect.get(target, prop)
  },
  set(target, prop, value) { // 对象本身 get的属性 修改的值
    console.log(target, prop, value, 'set');
    return Reflect.set(target, prop, value);
  }
})

setUp

  • 执行时机

    • beforeCreate 之前执行(一次),此时组件还没有创建
    • this 是 undefined,不可以通过this访问实例
  • 返回值

    • 一般都会淡会一个对象: 为模板提供数据
    • 返回的对象属性会于=与data函数返回的对象属性合并成为组件对象
    • 返回的方法会与methods中的方法合并为组件方法
    • 若有重复 setup 中的优先
    • 注意:
  • 一般不要混合使用: methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问data和methods
  • setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性数据
  • 参数
    • setup(props,context) / setup(props,{attrs,slots,emit})
    • props: 包含props配置声明,且传入了所有属性的对象,不能解构,结构后失去响应式
    • attrs: 包含不在props配置中声明的属性对象,相当于 this.$attrs
    • slots: 包含所有传入插槽内容的对象,相当于 this.$slots
    • emit: 用来分发自定义事件的函数, 相当于this.$emit

reactive 与 ref

用来生成响应式数据的Api

ref的本质还是通过reactive创建的响应式数据

  • ref 用来处理基本数据类型,reactive 用来处理对象(递归深度响应时式)
  • ref的数据操作: 在js中要.value, 在模板中不需要(内部解析模板时会自动添加.value)

watchEffect(vue3)

  • 与 watch 有什么不同?

    • 第一点我们可以从示例代码中看到 watchEffect 不需要指定监听的属性,他会自动的收集依赖, 只要我们回调中引用到了 响应式的属性, 那么当这些属性变更的时候,这个回调都会执行,而 watch 只能监听指定的属性而做出变更(v3开始可以同时指定多个)。
    • 第二点就是 watch 可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的。
    • 第三点是 watchEffect 如果存在的话,在组件初始化的时候就会执行一次用以收集依赖(与computed同理),而后收集到的依赖发生变化,这个回调才会再次执行,而 watch 不需要,因为他一开始就指定了依赖。
  • 停止监听

    • watchEffect 会返回一个用于停止这个监听的函数
    • 如果 watchEffect 是在 setup 或者 生命周期里面注册的话,在组件取消挂载的时候会自动的停止掉
    const stop = watchEffect(() => {
      /* ... */
    })
    
    // later
    stop()
    
  • side effect

    什么是 side effect ,不可预知的接口请求就是一个 side effect

    • 假设我们现在用一个用户ID去查询用户的详情信息,然后我们监听了这个用户ID, 当用户ID 改变的时候我们就会去发起一次请求,这很简单,用watch 就可以做到。 但是如果在请求数据的过程中,我们的用户ID发生了多次变化,那么我们就会发起多次请求,而最后一次返回的数据将会覆盖掉我们之前返回的所有用户详情。这不仅会导致资源浪费,还无法保证 watch 回调执行的顺序。而使用 watchEffect 我们就可以做到
    • onInvalidate(fn)传入的回调会在 watchEffect 重新运行或者 watchEffect 停止的时候执行
watchEffect(() => {
  // 异步api调用,返回一个操作对象
  const apiCall = someAsyncMethod(props.userID)

  onInvalidate(() => {
    // 取消异步api的调用。
    apiCall.cancel()
  })
})

生命周期

v2


v2生命周期

v3


v3生命周期
option Api components Api
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onBeforeMount
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated

toRefs

  • 把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref

  • 应用: 当从合成函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用

问题: reactive 对象解构所有属性值都是非响应式的(setup 的参数props解构同理)
解决: 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性

  function useReatureX() {
    const state = reactive({
      foo2: "a",
      bar2: "b",
    });
    setTimeout(() => {
      state.foo2 += "++";
      state.bar2 += "++";
    }, 2000);
    return toRefs(state);
  }

  setup() {
    const {foo2, bar2} = useReatureX();
    return {foo2, bar2};
  }

ref获取元素

让输入框自动获取焦点

<template>
  <h2>App</h2>
  <input type="text">---
  <input type="text" ref="inputRef">
</template>

<script lang="ts">
import { onMounted, ref } from 'vue'
/* 
ref获取元素: 利用ref函数获取组件中的标签元素
功能需求: 让输入框自动获取焦点
*/
export default {
  setup() {
    const inputRef = ref<HTMLElement|null>(null)

    onMounted(() => {
      inputRef.value && inputRef.value.focus()
    })

    return {
      inputRef
    }
  },
}
</script>

自定义hook函数

  • 使用Vue3的组合API封装的可复用的功能函数
  • 自定义hook的作用类似于vue2中的mixin技术
  • 自定义Hook的优势: 很清楚复用功能代码的来源, 更清楚易懂

收集用户鼠标点击的页面坐标

import { ref, onMounted, onUnmounted } from 'vue'
/* 
收集用户鼠标点击的页面坐标
*/
export default function useMousePosition () {
  // 初始化坐标数据
  const x = ref(-1)
  const y = ref(-1)

  // 用于收集点击事件坐标的函数
  const updatePosition = (e: MouseEvent) => {
    x.value = e.pageX
    y.value = e.pageY
  }

  // 挂载后绑定点击监听
  onMounted(() => {
    document.addEventListener('click', updatePosition)
  })

  // 卸载前解绑点击监听
  onUnmounted(() => {
    document.removeEventListener('click', updatePosition)
  })

  return {x, y}
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容