> 웹 프론트엔드 > View.js > vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

WBOY
풀어 주다: 2022-01-31 06:00:31
앞으로
4074명이 탐색했습니다.

이 기사는 라이프사이클 변경, 인스턴스 변경, 메소드 변경 등을 포함하여 vue3과 vue2의 차이점에 대한 지식을 제공합니다. 모든 사람에게 도움이 되기를 바랍니다.

vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

1. 라이프 사이클 변경: 3.x(상위) 2.x(하위)

vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)
vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)과 vue2 사이에서 라이프 사이클 기능이 소멸되는 것을 보는 것은 어렵지 않습니다. 0 수시로 변경되는 내용이 있습니다:

beforeDestroy --> beforeUnmount
destroyed --> unmounted
로그인 후 복사
其他的区别主要在于书写使用的语言上的差别
在ts中使用 class 类组件书写可以 参考 vue-class-component 或者 vue-property-decorator
书写的风格和vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)的选项式区别不大。
如果使用js书写代码 则应当使用组合式。
로그인 후 복사

구체적인 변경으로 인해 발생하는 문제는 아래 조합 작성 방법에서 설명하겠습니다.

2. 전역 변수 정의 방법 변경

// 之前(Vue 2.x)
Vue.prototype.$http = () => {}
Vue.prototype.url= 'http://123'
// 之后(Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {}
app.config.globalProperties.url= 'http://123'
로그인 후 복사

3. vue 인스턴스 생성 변경

//=======vue3.x
//使用createApp函数来实例化vue,
//该函数接收一个根组件选项对象作为第一个参数
//使用第二个参数,我们可以将根 prop 传递给应用程序
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App,{ userName: "blackLieo" })
.use(store)
.use(router)
.mount('#app')  
//由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法,这些方法可以在以下部分中找到。

//=======vue2.x
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
 Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
로그인 후 복사

4. 슬롯 사용 변경

//================vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)使用插槽基本上直接使用slot进行操作//其中vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)经历了两次更迭,2.6.0版本slot升级为v-slot<p>
    <slot></slot> // 具名 作用域插槽
    <slot></slot> //默认插槽</p>//父组件调用该组件<test>
    <template>
       <p>默认插槽</p>
    </template>
    // 作用域插槽
    <template>
       <el-form>
         <el-form-item>
           <el-link>{{ current.id }}</el-link>
         </el-form-item>
         <el-form-item>
           <el-link>{{ current.name }}</el-link>
         </el-form-item>
         <el-form-item>
           <el-link>{{ current.label }}</el-link>
         </el-form-item>
         <el-form-item>
           <el-link>{{ current.group }}</el-link>
         </el-form-item>
         <el-form-item>
           <el-link>{{ current.runtime }}</el-link>
         </el-form-item>
         <el-form-item>
           <el-link>{{ current.category }}</el-link>
         </el-form-item>
       </el-form>
     </template>
 </test>

 
 //==============vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)使用插槽//在vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)中,插槽使用v-slot 简写用#<p>	
   <slot></slot>
   <slot></slot></p><helloworld>
    <template> // 可以写为v-slot:default  #后面跟的是插槽名称
       <p>默认插槽</p>
    </template>
    //作用域插槽
    <template> // 可以写为v-slot:test="newData"
      <p>{{ newData.aa }}</p>
      <p>{{ newData.bb }}</p>
    </template></helloworld>//一个组件里面具有多个插槽时,一定要带上名称,否则可能会导致作用域错乱
로그인 후 복사

5. Vue에서 구현하세요. 2 사용자 지정 지시문:
// 注册一个全局自定义指令 `v-focus`Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }})
로그인 후 복사

Vue 2에서는 다음과 같은 선택적 후크를 통해 사용자 지정 지시문이 생성됩니다.

bind: 지시문이 요소에 처음 바인딩될 때 한 번만 호출됩니다. 여기에서 일회성 초기화 설정을 수행할 수 있습니다.
    inserted: 바인딩된 요소가 상위 노드에 삽입될 때 호출됩니다(상위 노드만 존재하도록 보장되지만 반드시 문서에 삽입될 필요는 없습니다).
  • update: 구성 요소의 VNode가 업데이트될 때 호출되지만 하위 VNode가 업데이트되기 전에 발생할 수 있습니다. 지시어의 값은 변경되었을 수도 있고 변경되지 않았을 수도 있습니다. 하지만 업데이트 전과 후의 값을 비교하여 불필요한 템플릿 업데이트를 무시할 수 있습니다(자세한 후크 기능 매개 변수는 아래 참조).
  • comComponentUpdated: 명령어가 있는 구성 요소의 VNode와 해당 하위 VNode가 모두 업데이트된 후에 호출됩니다.
  • unbind: 명령이 요소에서 바인딩 해제될 때 한 번만 호출됩니다.
  • Vue 3에서는 사용자 정의 지침의 API가 구성 요소 수명 주기 변경과 마찬가지로 더 나은 의미를 위해 변경되었습니다.


Vue3에서는 다음과 같은 작업을 수행할 수 있습니다. 다음과 같이 명령을 사용자 정의하십시오: vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

const { createApp } from "vue"const app = createApp({})app.directive('focus', {
    mounted(el) {
        el.focus()
    }})
로그인 후 복사
그런 다음 다음과 같이 템플릿의 모든 요소에 새로운 v-focus 명령을 사용할 수 있습니다:

<input>
로그인 후 복사

6.v-model 업그레이드

많은 v-model이 발생했습니다. Vue 3의 큰 변경 사항:
变更:在自定义组件上使用v-model时, 属性以及事件的默认名称变了
变更:v-bind的.sync修饰符在 Vue 3 中又被去掉了, 合并到了v-model里
新增:同一组件可以同时设置多个 v-model
新增:开发者可以自定义 v-model修饰符
로그인 후 복사

이에 대해 자세히 알아보고 vue2와 vue3을 비교해 보겠습니다. 구성 요소에 v-model 사용

예:

vue2 입력 상자의 양방향 바인딩은 실제로 값을 전달하는 것과 동일합니다. 속성 및 입력 이벤트가 트리거됩니다:


<input><input>


<input><input>
로그인 후 복사

현재 v-model은 구성 요소에 다른 속성을 사용하고 업데이트하고 싶지 않은 경우에만 구성 요소의 값 속성에만 바인딩될 수 있습니다. 입력을 트리거하여 값을 지정합니다.
但是在实际开发中,有些场景我们可能需要对一个 prop 进行 “双向绑定”, 这里以最常见的 dialog 为例子:dialog 挺合适属性双向绑定的,
外部可以控制组件的visible显示或者隐藏,组件内部关闭可以控制 visible属性隐藏,同时 visible 属性同步传输到外部。组件内部, 
当我们关闭dialog时, 在子组件中以 update:PropName 模式触发事件。
로그인 후 복사
이벤트는

this.$emit('update:visible', false)
로그인 후 복사
입니다. 그런 다음 데이터 업데이트를 위해 상위 구성 요소에서 이 이벤트를 들을 수 있습니다.

<el-dialog></el-dialog>
로그인 후 복사
로그인 후 복사
vue2 개발 과정에서 실제로 새로운 sync를 찾을 수 있으므로 v-bind.sync를 사용하여 구현을 단순화할 수도 있습니다.

<el-dialog></el-dialog>
로그인 후 복사
로그인 후 복사
위에서는 Vue2의 v-model 구현과 구성 요소의 양방향 바인딩을 언급했습니다. 속성이므로 Vue 3에서는 어떻게 달성됩니까?

Vue3에서 사용자 정의 구성 요소에 v-model을 사용하는 것은 modelValue 속성을 ​​전달하고 update:modelValue 이벤트를 트리거하는 것과 같습니다. sync,所以也可以使用v-bind.sync来简化实现:

<el-dialog></el-dialog>

<el-dialog></el-dialog>
로그인 후 복사

上面说了 Vue2 中v-model实现以及组件属性的双向绑定,那么在 Vue 3 中应该怎样实现的呢?
在 Vue3 中, 在自定义组件上使用v-model, 相当于传递一个modelValue 属性, 同时触发一个update:modelValue事件:

<el-dialog></el-dialog><el-dialog></el-dialog>
로그인 후 복사

如果要绑定属性名, 只需要给v-model传递一个参数就行, 同时可以绑定多个v-model

<template>
  <!-- 异步组件的使用 -->
  <asyncpage></asyncpage><script>import { defineAsyncComponent } from "vue";export default {
  components: {
    // 无配置项异步组件
    AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")),

    // 有配置项异步组件
    AsyncPageWithOptions: defineAsyncComponent({
   loader: () => import("./NextPage.vue"),
   delay: 200,
   timeout: 3000,
   errorComponent: () => import("./ErrorComponent.vue"),
   loadingComponent: () => import("./LoadingComponent.vue"),
 })
  },}</script></template>
로그인 후 복사

这个写法完全没有.sync什么事儿了, Vue 3 中抛弃了.sync写法, 统一使用v-model。

7.异步组件的使用

Vue3 中 使用 defineAsyncComponent 定义异步组件,配置选项 component 替换为 loader ,Loader 函数本身不再接收 resolve 和 reject 参数,且必须返回一个 Promise,用法如下:

   使用Composition API 解决我们在完成功能时,在 data、methods、computed 以及 mounted 中反复的跳转,他将零散分布的
   逻辑组合在一起维护,并可以将单独的逻辑再分为单独的文件
로그인 후 복사

8.Composition API

<script>import { defineComponent, reactive } from "vue";export default defineComponent({
  beforeCreate() {
    console.log("----beforeCreate----");
  },
  created() {
    console.log("----created----");
  },
  setup() {
    const state = reactive({ count: 0 });
    console.log("----setup----");
    return {
      state,
    };
  },});</script>
로그인 후 복사

如果想要了解<script setup></script>语法糖,请移步 vue3 setup语法糖(部分总结)

我们先来了解一下Composition具有的API
vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

  • setup

setup 是 Vue3.x 新增的一个选项, 他是组件内使用 Composition API的入口。

setup 执行时机
通过一段代码 我们可以知道:

setup(props) {
    const { name } = props;
    console.log(name);
    const state = reactive({ count: 0 });
    return {
      state,
    };
  },
로그인 후 복사
로그인 후 복사

会出现如下所示的输出结果:
vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

setup 执行时机是在 beforeCreate

reactive用于处理对象的双向绑定,ref处理 js 基础类型或者处理对象的双向绑定。
注意refs
它接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property.value。
로그인 후 복사
로그인 후 복사
바인딩하려는 경우 속성 이름을 설정하려면 v-model에 매개변수만 전달하면 됩니다. 여러 v-model을 동시에 바인딩할 수 있습니다.
    <template>
      <p>
        </p>
    <p>计数:{{ num }}s</p>
        <p>主人年龄:{{ person.age }}</p>
        <p>主人姓名:{{ person.name }}</p>
        <p>动物类别:{{ animal.type }}</p>
        <p>动物名称:{{ animal.name }}</p>
        <p>动物年龄:{{ animal.age }}</p>
      </template><script>import { defineComponent, reactive, ref } from "vue";export default defineComponent({
      setup() {
        //使用ref声明基本类型
        const num = ref(0);
        //使用ref声明对象
        const person = ref({ age: 20, name: "张三" });
        //使用reactive声明对象
        const animal = reactive({ type: "猫", name: "小花", age: 5 });
        setTimeout(() => {
          person.value.age = person.value.age + 1;
          person.value.name = "李四";
          animal.age++;
        }, 1000);
        setInterval(() => {
          num.value++;
        }, 1000);
        return {
          num,
          animal,
          person,
        };
      },});</script>
    로그인 후 복사
    로그인 후 복사
  1. 이렇게 작성하면 됩니다. .sync와는 아무런 관련이 없습니다. 와, Vue 3에서는 .sync 작성 방법을 포기하고 v-model을 균일하게 사용했습니다. 7. 비동기 구성요소 사용
Vue3에서 DefineAsyncComponent를 사용하여 구성 옵션 구성요소는 로더로 대체됩니다. Loader 함수 자체는 더 이상 확인 및 거부 매개변수를 수신하지 않으며 사용법은 다음과 같습니다.

<template>
  <p>
    </p>
<p>计数:{{ num }}s</p>
    <p>主人年龄:{{ person.age }}</p>
    <p>主人姓名:{{ person.name }}</p>
    <p>动物类别:{{ atype }}</p>
    <p>动物名称:{{ aname }}</p>
    <p>动物年龄:{{ aage }}</p>
  </template><script>import { defineComponent, reactive, ref, toRefs } from "vue";export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const animal = reactive({ atype: "猫", aname: "小花", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      animal.aage++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      person,
      ...toRefs(animal),
    };
  },});</script>
로그인 후 복사
로그인 후 복사
8. Composition API🎜
import { reactive, readonly } from 'vue'

const original = reactive({ count: 0 })

const copy = readonly(original)

// 通过 original 修改 count,将会触发依赖 copy 的侦听器

original.count++

// 通过 copy 修改 count,将导致失败并出现警告
copy.count++ // 警告: "Set operation on key 'count' failed: target is readonly."
로그인 후 복사
로그인 후 복사
🎜<script setup></script> 구문 설탕에 대해 알고 싶다면 여기로 이동 vue3 설정 구문 Sugar(부분 요약)🎜🎜Composition의 API를 먼저 이해해 봅시다🎜vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)🎜🎜🎜🎜setup🎜🎜🎜🎜setup은 Vue3.x의 새로운 옵션입니다. 컴포넌트 내 Composition API의 입구입니다. 🎜🎜설정 실행 타이밍🎜 코드를 통해 알 수 있습니다: 🎜
import {
  defineComponent,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,} from "vue";export default defineComponent({
  //beforeCreate和created是vue2的
  beforeCreate() {
    console.log("------beforeCreate-----");
  },
  created() {
    console.log("------created-----");
  },
  setup() {
    console.log("------setup-----");
    // vue3.xvue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)写在setup中
    onBeforeMount(() => {
      console.log("------onBeforeMount-----");
    });
    onMounted(() => {
      console.log("------onMounted-----");
    });
    onBeforeUpdate(() => {
      console.log("------onBeforeUpdate-----");
    });
    onUpdated(() => {
      console.log("------onUpdated-----");
    });
    onBeforeUnmount(() => {
      console.log("------onBeforeUnmount-----");
    });
    onUnmounted(() => {
      console.log("------onUnmounted-----");
    });
    onErrorCaptured(() => {
      console.log("------onErrorCaptured-----");
    });
    onRenderTracked(() => {
      console.log("------onRenderTracked-----");
    });
    // 调试哪些数据发生了变化
    onRenderTriggered((event) => {
      console.log("------onRenderTriggered-----", event);
    });
  },});
로그인 후 복사
로그인 후 복사
🎜다음 출력이 나타납니다: 🎜🎜🎜setup 실행 시간은 beforeCreate 이전입니다. 자세한 내용은 나중에 설명하는 라이프 사이클을 참조하세요. . 🎜🎜🎜🎜setup 매개변수🎜🎜🎜🎜setup을 사용할 때 두 개의 매개변수를 허용합니다: 🎜
  • props: 组件传入的属性
  • context

setup 中接受的props是响应式的, 当传入新的 props 时,会及时被更新。
由于是响应式的, 所以不可以使用 ES6 解构,解构会消除它的响应式。
错误代码示例, 这段代码会让 props 不再支持响应式:

setup(props) {
    const { name } = props;
    console.log(name);
    const state = reactive({ count: 0 });
    return {
      state,
    };
  },
로그인 후 복사
로그인 후 복사

对于以上的的问题,我们可以在后面的toRefs进行解释。
现在我们就来讲一下:

  1. reactive、ref、toRefs、readonly

在 vue2.x 中, 定义数据都是在data中。
但是 Vue3.x 可以使用reactiveref来进行数据定义。
那么ref和reactive他们有什么区别呢?

reactive用于处理对象的双向绑定,ref处理 js 基础类型或者处理对象的双向绑定。
注意refs
它接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property.value。
로그인 후 복사
로그인 후 복사
<template>
  <p>
    </p>
<p>计数:{{ num }}s</p>
    <p>主人年龄:{{ person.age }}</p>
    <p>主人姓名:{{ person.name }}</p>
    <p>动物类别:{{ animal.type }}</p>
    <p>动物名称:{{ animal.name }}</p>
    <p>动物年龄:{{ animal.age }}</p>
  </template><script>import { defineComponent, reactive, ref } from "vue";export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const animal = reactive({ type: "猫", name: "小花", age: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      animal.age++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      animal,
      person,
    };
  },});</script>
로그인 후 복사
로그인 후 복사

我们绑定到页面是通过user.name,user.age;这样写感觉很繁琐,我们能不能直接将user中的属性解构出来使用呢?
答案是不能直接对user进行结构, 这样会消除它的响应式, 这里就和上面我们说props不能使用 ES6 直接解构就呼应上了。
那我们就想使用解构后的数据怎么办,解决办法就是使用toRefs
toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象。具体使用方式如下:

<template>
  <p>
    </p>
<p>计数:{{ num }}s</p>
    <p>主人年龄:{{ person.age }}</p>
    <p>主人姓名:{{ person.name }}</p>
    <p>动物类别:{{ atype }}</p>
    <p>动物名称:{{ aname }}</p>
    <p>动物年龄:{{ aage }}</p>
  </template><script>import { defineComponent, reactive, ref, toRefs } from "vue";export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const animal = reactive({ atype: "猫", aname: "小花", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      animal.aage++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      person,
      ...toRefs(animal),
    };
  },});</script>
로그인 후 복사
로그인 후 복사

有时我们想跟踪响应式对象 (ref 或 reactive) 的变化,但我们也希望防止在应用程序的某个位置更改它,这时候,我们就需要readonly
例如,当我们有一个被传递的响应式对象时,我们不想让它在传递的的时候被改变。为此,我们可以基于原始对象创建一个只读的 proxy 对象:

import { reactive, readonly } from 'vue'

const original = reactive({ count: 0 })

const copy = readonly(original)

// 通过 original 修改 count,将会触发依赖 copy 的侦听器

original.count++

// 通过 copy 修改 count,将导致失败并出现警告
copy.count++ // 警告: "Set operation on key 'count' failed: target is readonly."
로그인 후 복사
로그인 후 복사
  • vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)钩子

在最开始的时候,我们就看到了两张图,其中的变化我们可以总结一下

vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

我们可以看到beforeCreatecreatedsetup替换了(但是 Vue3 中你仍然可以使用, 因为 Vue3 是向下兼容的, 也就是你实际使用的是 vue2 的)。
其次,钩子命名都增加了on; Vue3.x 还新增用于调试的钩子函数onRenderTriggeredonRenderTricked
下面我们简单使用几个钩子, 方便大家学习如何使用,Vue3.x 中的钩子是需要从 vue 中导入的:

import {
  defineComponent,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,} from "vue";export default defineComponent({
  //beforeCreate和created是vue2的
  beforeCreate() {
    console.log("------beforeCreate-----");
  },
  created() {
    console.log("------created-----");
  },
  setup() {
    console.log("------setup-----");
    // vue3.xvue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)写在setup中
    onBeforeMount(() => {
      console.log("------onBeforeMount-----");
    });
    onMounted(() => {
      console.log("------onMounted-----");
    });
    onBeforeUpdate(() => {
      console.log("------onBeforeUpdate-----");
    });
    onUpdated(() => {
      console.log("------onUpdated-----");
    });
    onBeforeUnmount(() => {
      console.log("------onBeforeUnmount-----");
    });
    onUnmounted(() => {
      console.log("------onUnmounted-----");
    });
    onErrorCaptured(() => {
      console.log("------onErrorCaptured-----");
    });
    onRenderTracked(() => {
      console.log("------onRenderTracked-----");
    });
    // 调试哪些数据发生了变化
    onRenderTriggered((event) => {
      console.log("------onRenderTriggered-----", event);
    });
  },});
로그인 후 복사
로그인 후 복사

具体怎么使用,是干什么的请参考官方文档,这里就不一一赘述了。

  • watch 与 watchEffect 的用法

watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是惰性的,也就是说仅在侦听的源数据变更时才执行回调。

watch(source, callback, [options])
로그인 후 복사

参数说明:

  1. source: 可以支持 string,Object,Function,Array;
  2. 用于指定要侦听的响应式变量 callback:
  3. 执行的回调函数 options:支持 deep、immediate 和 flush 选项。

其实整体和原来的vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)有一定的相似性,基本参数没有发生大的改变。

接下来我会分别介绍这个三个参数都是如何使用的, 如果你对 watch 的使用不明白的请往下看:

//监听reactive对象:watch(
      () => animal.aage,
      (curAge, preAge) => {
        console.log("新值:", curAge, "老值:", preAge);
      }
    );//监听ref变量
 watch(num, (newVal, oldVal) => {
      console.log("新值:", newVal, "老值:", oldVal);
    });
    //多个值的监听
 watch([() => animal.aage, num], ([curAge, newVal], [preAge, oldVal]) => {
      console.log("新值:", curAge, "老值:", preAge);
      console.log("新值:", newVal, "老值:", oldVal);
    });
    //监听对象复杂时,请使用深度监听 让函数的第三个参数为deep:truewatch(
      () => state.animal,
      (newType, oldType) => {
        console.log("新值:", newType, "老值:", oldType);
      },
      { deep: true }
    );
로그인 후 복사

默认情况下,watch 是惰性的, 那什么情况下不是惰性的, 可以立即执行回调函数呢?其实使用也很简单, 给第三个参数中设置
immediate: true即可。

//停止监听函数
   const stopWatchRoom = watch(
      () => state.animal,
      (newType, oldType) => {
        console.log("新值:", newType, "老值:", oldType);
      },
      { deep: true }
    );
    setTimeout(() => {
      // 停止监听
      stopWatchRoom();
    }, 3000);
로그인 후 복사

还有一个监听函数watchEffect,介绍一下watchEffect,看看它的使用和watch究竟有何不同,在上面代码的基础上,我们来编写。

watchEffect(() => {
      console.log(num);
    });
로그인 후 복사

执行结果首先打印一次num值;然后每隔一秒,打印num值。
从上面的代码可以看出, 并没有像watch一样需要先传入依赖,watchEffect会自动收集依赖, 只要指定一个回调函数。在组件初始化时, 会先执行一次来收集依赖, 然后当收集到的依赖中数据发生变化时, 就会再次执行回调函数。所以总结对比如下:

  • watchEffect 不需要手动传入依赖
  • watchEffect 会先执行一次用来自动收集依赖
  • watchEffect无法获取到变化前的值, 只能获取变化后的值

9.Hooks

在之前vue用的mixin,所谓的混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
现在的vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)提供了一种新的东西 vue-hooks。具体的vue-hooks,请参考网上教程

为什么产生了hooks
首先从class-component/vue-options说起:

  • 跨组件代码难以复用
  • 大组件,维护困难,颗粒度不好控制,细粒度划分时,组件嵌套存层次太深影响性能
  • 类组件,this不可控,逻辑分散,不容易理解
  • mixins具有副作用,逻辑互相嵌套,数据来源不明,且不能互相消费

当一个模版依赖了很多mixin的时候,很容易出现数据来源不清或者命名冲突的问题,而且开发mixins的时候,逻辑及逻辑依赖的属性互相分散且mixin之间不可互相消费。这些都是开发中令人非常痛苦的点。
hooks存在以下优势:

  • 允许hooks间相互传递值
  • 组件之间重用状态逻辑
  • 明确指出逻辑来自哪里

我们先来封装一个hooks,假如这个hooks是一个实现年龄加减,获取双倍年龄的函数。用单独的文件存储 bus/useAge.ts

import { ref, Ref, computed } from "vue";type CountResultProps = {
  age: Ref<number>;
  doubleAge: Ref<number>;
  increase: (curAge?: number) => void;
  decrease: (curAge?: number) => void;};export default function useCount(initValue = 20): CountResultProps {
  const age = ref(initValue);
  const increase = (curAge?: number): void => {
    if (typeof curAge !== "undefined") {
      age.value += curAge;
    } else {
      age.value += 1;
    }
  };
  const doubleAge = computed(() => age.value * 2);
  const decrease = (curAge?: number): void => {
    if (typeof curAge !== "undefined") {
      age.value -= curAge;
    } else {
      age.value -= 1;
    }
  };
  return {
    age,
    doubleAge,
    increase,
    decrease,
  };}</number></number>
로그인 후 복사

在组件里面调用该hooks

<template>
  <p>
    </p>
<p>计数:{{ num }}s</p>
    <p>主人年龄:{{ person.age }}</p>
    <p>主人姓名:{{ person.name }}</p>
    <p>动物类别:{{ atype }}</p>
    <p>动物名称:{{ aname }}</p>
    <p>动物年龄:{{ aage }}</p>
    <p>count: {{ age }}</p>
    <p>双倍年龄: {{ doubleAge }}</p>
    <p>
      <button>加1</button>
      <button>减一</button>
    </p>
  </template><script>import {
  defineComponent,
  reactive,
  ref,
  toRefs,
  watch,
  watchEffect,} from "vue";import useAge from "../bus/useAge.ts";export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const animal = reactive({ atype: "猫", aname: "小花", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      animal.aage++;
      animal.aname = "小橘";
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    const { age, doubleAge, increase, decrease } = useAge(22);
    return {
      num,
      person,
      ...toRefs(animal),
      age,
      doubleAge,
      increase,
      decrease,
    };
  },});</script>
로그인 후 복사

10.vue2.x 与vue3.x的响应式数据对比

在vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)中,应该很多人都使用了$set这个东西吧。
数据更新了,页面为什么不变化呢?什么时候我们用$forceUpdate强制更新呢?
在vue2.x中,实现数据监听使用的是Object.defineProperty。而vue3.x使用的是Proxy

  1. Object.defineProperty只能劫持对象的属性, 而 Proxy 是直接代理对象

由于Object.defineProperty只能劫持对象属性,需要遍历对象的每一个属性,如果属性值也是对象,就需要递归进行深度遍历。
但是Proxy 直接代理对象, 不需要遍历操作

  1. Object.defineProperty对新增属性需要手动进行Observe

因为Object.defineProperty劫持的是对象的属性,所以新增属性时,需要重新遍历对象,
对其新增属性再次使用Object.defineProperty进行劫持。也就是 Vue2.x
中给数组和对象新增属性时,需要使用$set才能保证新增的属性也是响应式的,
$set内部也是通过调用Object.defineProperty去处理的。

  1. Proxy有多种拦截方法,如apply,deleteProperty等等,是Object.defineProperty()不具备的。
  2. Proxy是返回值是一个对象,可以直接进行操作,而defineProperty()要先遍历所有对象属性值才能进行操作。
    但是相对来说,Object.defineProperty()兼容性高一些。

11.Teleport

Teleport 是 Vue3.x 新推出的功能

Teleport 是什么呢?

Teleport 就像是哆啦 A 梦中的「任意门」,任意门的作用就是可以将人瞬间传送到另一个地方。有了这个认识,我们再来看一下为什么需要用到 Teleport 的特性呢,看一个小例子:

例如我们在使用Dialog组件时,我们实际开发中经常会使用到 Dialog,此时Dialog就被渲染到一层层子组件内部,处理嵌套组件的定位、z-index和样式都变得困难。但是组件希望位于页面的最上方,这时候我们将Dialog组件挂载在body上面是最好控制的,我们能够很好的通过zIndex来控制Dialog的位置,当他嵌套在templat里面的时候就不那么容易了。简单来说就是,即希望继续在组件内部使用Dialog,又希望渲染的 DOM 结构不嵌套在组件内部的 DOM 中。

此时就需要 Teleport 上场,我们可以用<teleport></teleport>包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方。

<template>
  <p>
    </p>
<p>计数:{{ num }}s</p>
    <p>主人年龄:{{ person.age }}</p>
    <p>主人姓名:{{ person.name }}</p>
    <p>动物类别:{{ atype }}</p>
    <p>动物名称:{{ aname }}</p>
    <p>动物年龄:{{ aage }}</p>
    <p>count: {{ age }}</p>
    <p>倍数: {{ doubleAge }}</p>
    <p>
      <button>加1</button>
      <button>减一</button>
    </p>
    <el-button>点击打开 Dialog</el-button>    >
    <teleport>
      <el-dialog>
        <span>这是一段信息</span>
        <template>
          <span>
            <el-button>取 消</el-button>
            <el-button>确 定</el-button>            >
          </span>
        </template>
      </el-dialog>
    </teleport>
  </template><script>import {
  defineComponent,
  reactive,
  ref,
  toRefs,} from "vue";export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    const dialogVisible = ref(false);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const animal = reactive({ atype: "猫", aname: "小花", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      animal.aage++;
      animal.aname = "小橘";
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);

    return {
      dialogVisible,
      num,
      person,
      ...toRefs(animal),
    };
  },});</script>
로그인 후 복사

我们可以很清楚的看到teleport上有一个to属性,这个属性是讲当前节点传送到制定位置去的。位置应该传送到哪里呢?
答案就是在index.html上面
下面是我们的首页 你会看到有一个p的ID名为dialogLL,teleport就将节点挂载在这里来了

nbsp;html>
  
    <meta>
    <link>
    <meta>
    <title>Vite App</title>
  
  
    <p></p>
    <p></p>
    <script></script>
  
로그인 후 복사

如图所示:
vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

12.Suspense

Suspense是 Vue3.x 中新增的特性, 那它有什么用呢?我们通过 Vue2.x 中的一些场景来认识它的作用。 Vue2.x 中应该经常遇到这样的场景:

<template>
  <p>
    </p>
<p>...</p>
    <p>加载中...</p>
  </template>
로그인 후 복사

在前后端交互获取数据时, 是一个异步过程,一般我们都会提供一个加载中的动画,当数据返回时配合v-if来控制数据显示。
它提供两个template slot, 刚开始会渲染一个 fallback 状态下的内容, 直到到达某个条件后才会渲染 default 状态的正式内容, 通过使用
Suspense组件进行展示异步渲染就更加的简单。
具体的使用,我们可以用下面的例子来表示:
这是需要等待取值完成的的组件:

<template>
  <h1>{{ getData.result }}</h1></template><script>export default {
  name: "NewModel",
  async setup() {
    let getData = await new Promise((resolve) => {
      setTimeout(() => {
        return resolve({ result: "OK" });
      }, 3000);
    });
    return {
      getData,
    };
  },};</script>
로그인 후 복사

在其他组件内调用它,当等待取值的组件取值完成后,会将loading状态变为OK状态

<template>
  <p>
    <suspense>
      <template>
        <newsuspense></newsuspense>
      </template>
      <template>
        <h1>Loadding...</h1>
      </template>
    </suspense>
  </p></template><script>import NewSuspense from "./suspens.vue";export default {
  name: "AppMain",
  components: {
    NewSuspense,
  },};</script><style></style>
로그인 후 복사

效果如图:
vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)

13.片段(Fragment)

在 Vue2.x 中, template中只允许有一个根节点:

<template>
    <p>
        <span></span>
        <span></span>
    </p></template>
로그인 후 복사

但是在 Vue3.x 中,你可以直接写多个根节点:

<template>
    <span></span>
    <span></span></template>
로그인 후 복사

14.Tree-Shaking变化

Vue3.x 在考虑到 tree-shaking的基础上重构了全局和内部 API, 表现结果就是现在的全局 API 需要通过 ES Module的引用方式进行具名引用, 比如在 Vue2.x 中,我们要使用 nextTick:

// vue2.ximport Vue from "vue"Vue.nextTick(()=>{
    ...})或者 
this.nextTick(()=>{
    ...})
로그인 후 복사

Vue.nextTick() 是一个从 Vue 对象直接暴露出来的全局 API,其实 $nextTick() 只是 Vue.nextTick() 的一个简易包装,只是为了方便而把后者的回调函数的 this 绑定到了当前的实例。
在 Vue3.x 中改写成这样:

import { nextTick } from "vue"nextTick(() =>{
    ...})
로그인 후 복사

受影响的 API

这是一个比较大的变化, 因为以前的全局 API 现在只能通过具名导入,这一更改会对以下 API 有影响:

  1. Vue.nextTick
  2. Vue.observable(用 Vue.reactive 替换)
  3. Vue.version
  4. Vue.compile(仅限完整版本时可用)
  5. Vue.set(仅在 2.x 兼容版本中可用)
  6. Vue.delete(与上同)

相关推荐:vue.js视频教程

위 내용은 vue3의 고전적인 기법과 vue2와의 차이점 정리 및 공유(부분)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
vue
원천:csdn.net
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿