vue3入门(学习之路一)

371 阅读5分钟

1、vue3变化

  1. 新增了三个组件:Fragment 支持多个根节点、Suspense 可以在组件渲染之前的等待时间显示指定内容、Teleport 可以让子组件能够在视觉上跳出父组件(如父组件overflow:hidden)。
  2. 新增指令 v-memo,可以缓存 html 模板,比如 v-for 列表不会变化的就缓存,简单说就是用内存换时间。
  3. 新增 Composition API 可以更好的逻辑复用和代码组织,同一功能的代码不至于像以前一样太分散,虽然 Vue2 中可以用 minxin 来实现复用代码,但也存在问题,比如方法或属性名会冲突,代码来源也不清楚等。
  4. Proxy 代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等13种方法。
  5. 重构了虚拟 DOM,在编译时会将事件缓存、将 slot 编译为 lazy 函数、保存静态节点直接复用(静态提升)、以及添加静态标记、Diff 算法使用 最长递增子序列 优化了对比流程,使得虚拟 DOM 生成速度提升 200%
  6. 支持在 <style></style> 里使用 v-bind,给 CSS 绑定 JS 变量(color: v-bind(str))。
  7. setup 代替了 beforeCreate 和 created 这两个生命周期。
  8. 新增了开发环境的两个钩子函数,在组件更新时 onRenderTracked 会跟踪组件里所有变量和方法的变化、每次触发渲染时 onRenderTriggered 会返回发生变化的新旧值,可以让我们进行有针对性调试。

2、入口文件main.js

vue2

import Vue from 'vue'
import App from './App'
import store from './store'
import routes from './router'
Vue.config.productionTip = false
new Vue({
   router,
   store,
   render: (h) => h(App)
}).$mount('#app')

vue3

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')

区别:vue2引入的是vue构造函数,vue3是createApp工厂函数。vue2的写法在vue3不能兼容

3、支持碎片

在组件可以拥有多个根节点。

<template>
  <div id="nav">
    <router-link to="/">home</router-link>
  </div>
  <router-view/>
</template>

区别:vue2只能在在div根标签里面写东西,vue3可以有多个根标签

4、生命周期

60f518fa89ba44bb8b59911ecd65a8a4_tplv-k3u1fbpfcp-watermark.jpg (图来自网络) 由于vue3是向下兼容的,所以vue3中仍可以使用beforeCreate和created

注意:vue3中的生命周期需要从 vue 中导入

setup() {
    onBeforeMount(() => {
      console.log('onBeforeMount')
    })
},

因为 setup 是围绕 beforeCreatecreated 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。

5、Composition API

vue2中使用OptionAPI

Options API缺点:只能固定用 datacomputedmethods 等选项组织代码,在组件越来越复杂的时候,一个功能相关的属性和方法就会在文件上中下到处都有,很分散,变越来越难维护。虽然可以用 minxin 来做逻辑的提取复用,但是 minxin 里的属性和方法名会和组件内部的命名冲突,还有当引入多个 minxin 的时候,我们使用的属性或方法是来于哪个 minxin 也不清楚。

vue3Composition API

官网介绍:通过创建 Vue 组件,我们可以将界面中重复的部分连同其功能一起提取为可重用的代码段。仅此一项就可以使我们的应用在可维护性和灵活性方面走得相当远。

705ac8db86de4aa8a9b40f59be48e42a.png (图来自网络)

5.1、setUp

  • 新的 setup 选项在组件创建之前beforeCreat之前执行,就将作为组合式 API 的入口。setup 函数只会在组件初始化的时候执行一次。因为setUp在beforeCreate之前执行,实例还没生成,所以在setUp中无法使用this
setup(props, context) { ... }

setUp接受两个参数:

  • props: 组件传入的属性,setup 中接受的props是响应式的, 当传入新的 props 时,会及时被更新。由于是响应式的, 所以不可以使用es6解构赋值,解构会消除它的响应式。

    如果需要解构可使用toRefs函数

    import { toRefs } from 'vue'setup(props) {
      const { title } = toRefs(props)
    ​
      console.log(title.value)
    }
    
  • context:context 是一个普通 JavaScript 对象,不是响应式的所以可以使用 ES6 解构。context 对象有四个属性:attrs(等同于 attrs)slot(等同于attrs)、`slot`(等同于 slots) 、emit(等同于 $emit),expose(暴露公共 property (函数))

注意:Vue2(data、methos、computed…)中可以访问到setup中的属性、方法。但在setup中不能访问到V2配置(data、methos、computed…)。如果有重名,setup优先

5.2、响应性API reactive与响应性API ref

5.2.1、reactive

返回对象的响应式副本

使用步骤

  1. 从vue框架中导入reactive函数
  2. 在setup函数中调用reactive函数并将想要变成响应式的对象数据当成参数传入
  3. 在setup函数中把reactive函数调用完毕之后的返回值以对象的形式返回出去
import { reactive } from '@vue/reactivity';
export default {
  setup() {
    const obj = reactive({ count: 0 })
    return {
        obj
    }
  }
}

5.2.2、ref

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值。

使用步骤

  1. 从vue框架中导出ref函数
  2. 在setup函数中调用ref函数并传入数据(简单类型或者复杂类型)
  3. 在setup函数中把ref函数调用完毕的返回值以对象的形式返回出去。

注意: 在setup函数中使用ref结果,需要通过.value 访问,模板中使用不需要加.value

import { ref  } from '@vue/reactivity';
export default {
  setup() {
    let money = ref(100)
    console.log(money.value)
    return {
        money
    }
  }
}

5.2.3、reactive 对比 ref

(reactive用于处理对象的双向绑定,ref则处理 js 基础类型的双向绑定) (掘金)

ref与reactive的区别

  • ref用来定义:基本类型数据(ref可以定义对象或数组的,它只是内部自动调用了reactive来转换。)。
  • ref通过Object.defineProperty()getset来实现响应式(数据劫持)。
  • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
  • reactive用来定义:对象或数组类型数据
  • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源代码内部的数据。
  • reactive定义的数据:操作数据与读取数据:均不需要.value

5.2.4 toRef()函数

toRef()函数用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象,简单说就是对reavtive()函数解构返回。

setup() {
    const data = reactive({
        name: ['张三', '李四', '王五'],
        selectName: '',
        selectFn: (index:number) => {
            data.selectName = data.name[index]
        }
    });
    return {
      ...toRefs(data),
    }
}

6、watch和watchEffect()

6.1、watch

watch 作用是对传入的某个或多个值的变化进行监听;触发时会返回新值和老值;也就是说第一次不会执行,只有变化时才会重新执行。

vue3的watch监听单个值:

import {watch} from 'vue' // vue3使用watch必须先引用watch(a, (newVal, oldVal) => {
    console.log(newVal, '===', oldVal)
})

wacth函数接收两个参数,第一个参数是我们要检测的值,第二个是回调函数,和以前一样拥有新旧两个值。

vue3的watch同时监听多个值:

import {watch} from 'vue'watch([a, b], ([newValA, newValB], [oldValA, oldValB]) => {
    console.log(newValA, newValB, '===', oldValA, oldValB)
})

注意:watch只能监听,1:拥有getter/setter属性的值。2:一个ref属性,也就是通过ref()申明的数据。3:一个reactive()函数返回的对象。4:一个数组。 所以监听reactive()函数定义的将会直接报错。

如果想要监听reactive函数声明的值,可以通过一个函数直接return回来一个新值

const data = reactive({
  name: '张三',
  age: 1
})
watch(() => data.age, ([newValA, newValB], [oldValA, oldValB]) => {
      console.log(newValA, newValB, '===', oldValA, oldValB)
    })

6.2、watchEffect

官方解释:立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

const count = ref(0)
​
watchEffect(() => console.log(count.value))
​
setTimeout(() => {
  count.value++
}, 100)

watchEffect 是传入一个立即执行函数,所以默认第一次也会执行一次;不需要传入监听内容,会自动收集函数内的数据源作为依赖,在依赖变化的时候又会重新执行该函数,如果没有依赖就不会执行;而且不会返回变化前后的新值和老值

6.3、watch和watchEffect共享的行为

watch与 watchEffect共享停止侦听清除副作用 (相应地 onInvalidate 会作为回调的第三个参数传入)、副作用刷新时机侦听器调试行为。

待续。。。