Chapter 12 Vue3 Development

Vue 3.0

What Vue brings

On September 18, 2020, Vue.js released version 3.0

  1. performance improvement
    • Bundle size reduced by 41%
    • 55% faster initial render, 133% faster update render
    • 54% less memory
  2. Source code upgrade
    • Use Proxy instead of defineProperty to achieve responsiveness
    • Rewrite the implementation of virtual DOM and Tree-Shaking
  3. Embracing TypeScript
  4. new features
    • Composition API (composition API)
      • setup configuration
      • ref and reactive
      • watch与watchEffect
      • provide and inject
    • new built-ins
      • Fragment
      • Teleport
      • Suspense
    • other changes
      • new lifecycle hook
      • The data option should always be declared as a function
      • Remove keyCode support as v-on modifier

1. Create a Vue3.0 project

Node version needs to be greater than 16 or higher

1. Use vue-cli to create

Official documentation: https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
insert image description here
or
insert image description here

2. Use vite to create

Official document: https://v3.cn.vuejs.org/guide/installation.html#vite
official website of vite: https://vitejs.cn

  • What is vite? —— A new generation of front-end build tools
  • The advantages are as follows:
    1. In the development environment, no packaging operation is required, and quick cold start is possible
    2. Lightweight and fast hot reload (HMR) - faster partial refresh
    3. True on-demand compilation, no longer waiting for the entire application to be compiled
  • Comparison chart of traditional construction and vite construction
    The traditional construction mode is to package all resources and then go online

insert image description here

insert image description here

1. Create a project

insert image description here
or as follows:
insert image description here

2. Analyze the engineering structure

2.1, main.jsin the file
  1. The way Vue is introduced is different.
  2. There are different ways to create instance objects.
    insert image description here
2.2. App.vueIn the file

Allow no root tag

insert image description here

2. Common Composition API

Translate to composition API: https://link.juejin.cn/?target=https%3A%2F%2Fv3.cn.vuejs.org%2Fguide%2Fcomposition-api-introduction.html

In Vue2, we use the Options API, a configuration item-style API. We need to create a Vue instance, and then pass in a configuration object in it, which needs to write data, methods, watches, etc., and Vue3 proposes a new Composition API, combined API, we don't need to create a Vue instance directly, but create an app, and then import the required API as needed for use...

Sections 1 and 2 can be skipped first. After reading this chapter, it will be better to look at this comparison chart

1. Problems with Options API

When using the traditional (configuration API) in Vue2 , Options APIif you add or modify a requirement, you need to modify it in data, respectively .methodscomputed

insert image description here

2. Advantages of Composition API

In Vue3, we can organize our code and functions (combination) more elegantly. Let the code of related functions be organized together in a more orderly manner.

Composition API :https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0f9d33731796417c9b8035990e4e52cd~tplv-k3u1fbpfcp-watermark.awebp
https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dbee55cc74ba45e2b7883c78cf7aa691~tplv-k3u1fbpfcp-watermark.awebp

Don’t panic if you don’t understand, after learning the following content, you will understand when you come back~

3. Common Composition APIs

① kicked offsetup

1. Understanding: A new configuration item in Vue3.0, the value is a function.
2. setup is the "stage of performance" of all Composition APIs (combination APIs).
3. The components used in the components: data, methods, etc., must be configured in the setup.
4. Two return values ​​of the setup function:

  1. If an object is returned, the properties and methods in the object can be used directly in the template. (Focus!)
  2. If it returns a rendering function: you can customize the rendering content. (Understand) (not commonly used)
<template>
  <h1>博主的信息</h1>
  <h2>姓名:{
    
    {
    
    name}}</h2>
  <h2>年龄:{
    
    {
    
    age}}</h2>
  <h2>性别:{
    
    {
    
    gender}}</h2>
  <button @click="sayInfo">显示信息</button>
</template>

<script>
// import {
    
    h} from 'vue'
export default {
    
    
  name: "App",
  //此处只是测试一下setup,暂时不考虑响应式的问题。
  setup(){
    
    
    // 数据
    let name = "博客zhu虎康"
    let age = 18
    let gender = "男"

    // 方法
    function sayInfo(){
    
    
      alert(`你好${
    
    name},你太厉害了吧`)
    }
    return {
    
    
      name,age, gender,sayInfo
    }
    // return ()=> h('h1','虎康yyds')
  }
};
</script>

If the return is a rendering function
, the template you wrote in the template will not work, and the page will be rendered with the content in the h function you wrote

5, Note:

Try not to mix with Vue2.x configuration

  • Properties and methods in setup can be accessed in Vue2.x configuration (data, methos, computed...).
  • But Vue2.x configuration (data, methos, computed...) cannot be accessed in setup.
  • If there are duplicate names, setup takes precedence.

setup cannot be an async function, because the return value is no longer an object, but a promise, and the template cannot see the properties in the return object. (You can also return a Promise instance later, but it requires the cooperation of Suspense and asynchronous components)

The above data is not responsive data. If we modify it, the page will not be updated. How to define responsive data?

② ref function

RefImpl = reference + implement

1. Function: define a responsive data
2. Grammar:const xxx = ref(initValue)

  • Create a reference object (reference object, ref object for short) that contains responsive data .
  • Vue3 has different responses to different data, variable——RefImpl; collection {]——proxy
  • Data manipulation in JS:xxx.value
  • Read data in the template: No need for .value, directly:<div>{ {xxx}}</div>

3. Remarks:

  • The received data can be: basic type or object type.
  • Basic types of data: Responsiveness relies on getters and setters on the class to complete (we will see the source code later and you will know).
  • Object type data: internally "requests" a new function in Vue3.0 - the reactive function.
<template>
  <h1>博主的信息</h1>
  <h2>姓名:{
    
    {
    
     name }}</h2>
  <h2>年龄:{
    
    {
    
     age }}</h2>
  <h2>职业: {
    
    {
    
     job.type }}</h2>
  <h2>工资:{
    
    {
    
     job.salary }}</h2>
  <button @click="sayInfo">显示信息</button>
  <button @click="changeInfo">修改信息</button>
</template>

<script>
import {
    
     ref } from "vue";
export default {
    
    
  name: "App",
  setup() {
    
    
    // 数据
    let name = ref("虎康");
    let age = ref(18);
    let job = ref({
    
    
      type: "前端工程师",
      salary: "30K",
    });
    // 方法
    function sayInfo() {
    
    
      alert(`你好${
    
    name.value},你太厉害了吧,薪水${
    
    job.value.salary}这么高`);
    }
    function changeInfo() {
    
    
      name.value = "三十年后的虎康";
      age.value = 48;
      job.value.type = "工程师";
      job.value.salary = "200K";
    }
    return {
    
    
      name,
      age,
      job,
      sayInfo,
      changeInfo,
    };
  },
};
</script>

By looking at the source code, we can know that calling ref will return a RefImpl instance object, and there are getters and setters in the RefImpl class to detect data changes

function ref(value) {
    
    
    return createRef(value, false);
}

function createRef(rawValue, shallow) {
    
    
    if (isRef(rawValue)) {
    
    
        return rawValue;
    }
    return new RefImpl(rawValue, shallow);
}

class RefImpl {
    
    
    constructor(value, _shallow) {
    
    
        this._shallow = _shallow;
        this.dep = undefined;
        this.__v_isRef = true;
        this._rawValue = _shallow ? value : toRaw(value);
        this._value = _shallow ? value : convert(value);
    }
    get value() {
    
    
        trackRefValue(this);
        return this._value;
    }
    set value(newVal) {
    
    
        newVal = this._shallow ? newVal : toRaw(newVal);
        if (hasChanged(newVal, this._rawValue)) {
    
    
            this._rawValue = newVal;
            this._value = this._shallow ? newVal : convert(newVal);
            triggerRefValue(this, newVal);
        }
    }
}

③ reactive function

1. Function: Define an object type of responsive data (do not use it for basic types, use the ref function)
2. Syntax: const 代理对象= reactive(源对象)Receive an object (or array) and return a proxy object (the instance object of Proxy, referred to as proxy object)
3. The responsive data defined by reactive is "deep".
4. The internal ES6-based Proxy implementation operates on the internal data of the source object through the proxy object.

<template>
  <h1>博主的信息</h1>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
  <h2>年龄:{
    
    {
    
     yk.age }}</h2>
  <h2>职业: {
    
    {
    
     yk.job.type }}</h2>
  <h2>工资:{
    
    {
    
     yk.job.salary }}</h2>
  <h2>爱好:{
    
    {
    
     yk.hobby }}</h2>
  <h3>测试数据:{
    
    {
    
     yk.job.a.b.c }}</h3>
  <button @click="changeInfo">修改信息</button>
</template>

<script>
import {
    
     reactive } from "vue";
export default {
    
    
  name: "App",
  setup() {
    
    
    // 数据
    let yk = reactive({
    
    
      name: "虎康",
      age: 18,
      hobby: ["写博客", "学习", "看书"],
      job: {
    
    
        type: "前端工程师",
        salary: "30K",
        a: {
    
    
          b: {
    
    
            c: 666,
          },
        },
      },
    });

    // 方法
    function changeInfo() {
    
    
      yk.name = "三十年后的虎康";
      yk.age = 48;
      yk.job.type = "工程师";
      yk.job.salary = "200K";
      yk.job.a.b.c = 888;
      // 直接通过数组下标修改,可以触发响应式
      yk.hobby[0] = "写小说";
    }
    return {
    
    
      yk,
      changeInfo,
    };
  },
};
</script>

④ Responsive principle in Vue3.0

1. Responsiveness of Vue2.x

1.1. Implementation principle

  • Object type: Object.defineProperty()Intercept (data hijacking) by reading and modifying existing attribute values ​​of objects.

  • Array type: interception is achieved by overriding a series of methods for updating the array. (The change method of the array is wrapped).

Object.defineProperty(data, 'count', {
    
    
    get () {
    
    }, 
    set () {
    
    }
})

1.2. There are problems

  • When adding or deleting attributes, the interface will not be updated.

  • Modify the array directly through the subscript, and the interface will not be automatically updated.

  • solution

    Use Vue.set、Vue.deleteor vm.$set、vm.$deletethese API

insert image description here

Simulate responsiveness in Vue2

//源数据
let person = {
    
    
	name:'张三',
	age:18
}
//模拟Vue2中实现响应式
let p = {
    
    }
Object.defineProperty(p,'name',{
    
    
	configurable:true,
	get(){
    
     //有人读取name时调用
		return person.name
	},
	set(value){
    
     //有人修改name时调用
		console.log('有人修改了name属性,我发现了,我要去更新界面!')
		person.name = value
	}
})
Object.defineProperty(p,'age',{
    
    
	get(){
    
     //有人读取age时调用
		return person.age
	},
	set(value){
    
     //有人修改age时调用
		console.log('有人修改了age属性,我发现了,我要去更新界面!')
		person.age = value
	}
})
2. The responsiveness of Vue3.0

In the above example, we can see that the array can be modified through subscripts. Let’s test whether adding and deleting attributes works well in Vue3

<template>
 <h1>博主的信息</h1>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
  <h2 v-show="yk.age">年龄:{
    
    {
    
     yk.age }}</h2>
  <h2 v-show="yk.gender">性别:{
    
    {
    
     yk.gender }}</h2>
  <h2>职业: {
    
    {
    
     yk.job.type }}</h2>
  <h2>工资:{
    
    {
    
     yk.job.salary }}</h2>
  <h2>爱好:{
    
    {
    
     yk.hobby }}</h2>
  <h3>测试数据:{
    
    {
    
     yk.job.a.b.c }}</h3>
  <button @click="changeInfo">修改信息</button>
  <button @click="addGender">增加性别</button>
  <button @click="deleteAge">删除年龄</button>
</template>

<script>
import {
    
     reactive } from "vue";
export default {
    
    
  name: "App",
  setup() {
    
    
    // 数据
    let yk = reactive({
    
    
      name: "虎康",
      age: 18,
      hobby: ["写博客", "学习", "看书"],
      job: {
    
    
        type: "前端工程师",
        salary: "30K",
        a: {
    
    
          b: {
    
    
            c: 666,
          },
        },
      },
    });

    // 方法
    function changeInfo() {
    
    
      yk.name = "三十年后的";
      yk.age = 48;
      yk.job.type = "工程师";
      yk.job.salary = "200K";
      yk.a.b.c = 888;
      yk.hobby[0] = "写小说";
    }

    function addGender() {
    
    
      yk.gender = "男";
    }
    function deleteAge() {
    
    
      delete yk.age;
    }

    return {
    
    
      yk,
      changeInfo,
      addGender,
      deleteAge,
    };
  },
};
</script>

1. Implementation principle

  • Through Proxy (proxy): Intercept the change of any attribute in the object, including: reading and writing attribute values, adding attributes, deleting attributes, etc.
  • Through Reflect (reflection): operate on the properties of the source object.
  • Proxy and Reflect described in the MDN document:
    insert image description here

Regarding proxy and reflection, you can read this blog post
to simulate responsiveness in Vue3

let person = {
    
    
	name:'YK',
	age:18
}

const p = new Proxy(person,{
    
    
	//有人读取p的某个属性时调用
	get(target,propName){
    
    
		console.log(`有人读取了p身上的${
      
      propName}属性`)
       // return target[propName]
		return Reflect.get(target,propName)
	},
	//有人修改p的某个属性、或给p追加某个属性时调用
	set(target,propName,value){
    
    
		console.log(`有人修改了p身上的${
      
      propName}属性,我要去更新界面了!`)
        // target[propName] = value
		return Reflect.set(target,propName,value)
	},
	//有人删除p的某个属性时调用
	deleteProperty(target,propName){
    
    
		console.log(`有人删除了p身上的${
      
      propName}属性,我要去更新界面了!`)
		// return delete target[propName]
       return Reflect.deleteProperty(target,propName)
	}
})

⑤ reactive vs. ref

Comparison from the perspective of definition data

  1. ref is used to define: basic type data.
  2. reactive is used to define: object (or array) type data.
  3. Remarks: ref can also be used to define object (or array) type data, which will be automatically converted to a proxy object through reactive internally.

Comparison from a principle point of view

  1. ref implements responsiveness (data hijacking) through getters and setters in the class.
  2. reactive implements responsiveness (data hijacking) by using Proxy, and manipulates the data inside the source object through Reflect.

From the point of view of use

  1. Data defined by ref: .value is required to operate the data, and .value is not required for direct reading in the template when reading data.
  2. The data defined by reactive: operation data and read data: neither need .value.

⑥ Two points of attention for setup

1. Timing of setup execution

Executed once before beforeCreate, this is undefined.

2. Setup parameters
setup(props,context)

Print the two parameters (props, context) received by setup on the console, as follows

props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
context:上下文对象

attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
slots: 收到的插槽内容, 相当于 this.$slots
emit: 分发自定义事件的函数, 相当于 this.$emit
3. Test it

App component and HelloWorld component
1. The parent component passes attribute parameters to the child component

<template>
  <h1>博主的信息</h1>
  <HelloWorld msg="你好啊" school="ABC"></HelloWorld>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
    
    
  name: "App",
  components: {
    
     HelloWorld },
};
</script>
<template>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
</template>

<script>
import {
    
     reactive } from "@vue/reactivity";
export default {
    
    
  name: "HelloWorld",
  props: ['msg'], // 不写全会报警告
  setup(props, context) {
    
    
    let yk = reactive({
    
    
      name: "YK",
    });
    console.log('props-----',props);
    console.log()
    console.log('context.attrs-----', context.attrs)
    return {
    
     yk };
  },
};
</script>

2. Custom events

<template>
  <h1>博主的信息</h1>
  <HelloWorld @hello="showHelloMsg"></HelloWorld>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
    
    
  name: "App",
  setup() {
    
    
    function showHelloMsg(value) {
    
    
      alert(`你好啊,你触发了hello事件,我收到的参数是:${
     
     value}`);
    }
    return {
    
     showHelloMsg };
  },
  components: {
    
     HelloWorld },
};
</script>
<template>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
  <button @click="test">测试触发一下HelloWorld组件的Hello事件</button>
</template>

<script>
import {
    
     reactive } from "@vue/reactivity";
export default {
    
    
  name: "HelloWorld",
  emits:["hello"], // 不写能执行,但是会报警告
  setup(props, context) {
    
    
    let yk = reactive({
    
    
      name: "YK",
    });
    function test() {
    
    
      context.emit("hello", "**子组件的信息**");
    }
    return {
    
     yk,test };
  },
};
</script>

If received without the emits option, a warning will be reported

slot

default slot

<template>
  <h1>博主的信息</h1>
  <HelloWorld>
    <span>YK,你好</span>
  </HelloWorld>
</template>
<template>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
  <slot></slot>
</template>

named slot

<template>
  <h1>博主的信息</h1>
  <HelloWorld>
	<template v-slot:ykMsg>
		<span>YK,你好</span>
	</template>
  </HelloWorld>
</template>
<template>
  <h2>姓名:{
    
    {
    
     yk.name }}</h2>
  <slot name="ykMsg"></slot>
</template>

⑦ Computational attributes and monitoring

1. computed function

Consistent with the configuration function Vue2.xincomputed

wording

i

mport {
    
    computed} from 'vue'

setup(){
    
    
    ...
	//计算属性 —— 简写
    let fullName = computed(()=>{
    
    
        return person.firstName + '-' + person.lastName
    })
    //计算属性 —— 完整
    let fullName = computed({
    
    
        get(){
    
    
            return person.firstName + '-' + person.lastName
        },
        set(value){
    
    
            const nameArr = value.split('-')
            person.firstName = nameArr[0]
            person.lastName = nameArr[1]
        }
    })
}
2. Watch function: watch (who is being monitored, (monitoring callback), {monitoring configuration})
  • Complete writing:
    insert image description here

Define the data with multiple structures in person as follows, ref definition requires .value, reactive does not, but {deep:true} needs to be turned on
insert image description here
[general use case 3, monitor]

  • Consistent with the configuration function Vue2.xinwatch

  • Two small "pits":

    1. When monitoring the responsive data defined by reactive: oldValue cannot be obtained correctly, and deep monitoring is forcibly enabled (the deep configuration is invalid).
    2. When monitoring a certain attribute (must be an object) in the responsive data defined by reactive: the deep configuration is valid.

  • Case 1: Monitor the responsive data defined by ref

//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
    
    
	console.log('sum变化了',newValue,oldValue)
},{
    
    immediate:true})

If an object is defined with ref

watch(person.value,(newValue,oldValue)=>{
    
    
	console.log('person变化了',newValue,oldValue)
}) 

or this

watch(person,(newValue,oldValue)=>{
    
    
	console.log('person变化了',newValue,oldValue)
},{
    
    deep: true}) 
  • Case 2: Monitor the responsive data defined by multiple refs and place them in an array for unified monitoring
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
    
    
	console.log('sum或msg变化了',newValue,oldValue)
}) 
  • Case 3: Monitor the responsive data defined by reactive [generally use case 3 development]

If the watch monitors the reactive data defined by reactive, the oldValue cannot be obtained correctly! !
If the watch monitors the reactive data defined by reactive, the in-depth monitoring is forcibly enabled

watch(person,(newValue,oldValue)=>{
    
    
	console.log('person变化了',newValue,oldValue)
},{
    
    immediate:true,deep:false}) //此处的deep配置不再奏效
  • Situation 4: Monitor an attribute in the responsive data defined by reactive
//情况四:监视reactive定义的响应式数据对象中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
    
    
	console.log('person的job变化了',newValue,oldValue)
},{
    
    immediate:true,deep:true}) 
  • Situation 5: Monitor certain attributes in the responsive data defined by reactive, and place them in an array for unified monitoring
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
    
    
	console.log('person的job变化了',newValue,oldValue)
},{
    
    immediate:true,deep:true})
  • Special case
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
    
    
    console.log('person的job变化了',newValue,oldValue)
},{
    
    deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效

The third attribute of watch

  1. flush:'pre' : the default is pre, executed before dom update
  2. flush:'post': executed after dom update
  3. flush:'sync': execute synchronously with dom update

insert image description here

watch's clear callback

insert image description here

Stop monitoring. When we want to stop monitoring, we can call the following stop function.
watch itself is a function, that is, it returns a function

const stop = watch(num,
	(newValue,oldValue)=>{
    
     
	console.log(newValue,oldValue)
 })
3. watchEffect function
  • The routine of watch is: specify not only the attribute of monitoring, but also the callback of monitoring.

  • The routine of watchEffect is: no need to specify which attribute to monitor, which attribute is used in the monitoring callback, then which attribute to monitor.

  • watchEffect is a bit like computed:

    • But computed pays attention to the calculated value (the return value of the callback function), so the return value must be written.
    • And watchEffect pays more attention to the process (the function body of the callback function), so there is no need to write the return value.
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
    
    
    const x1 = sum.value
    const x2 = person.age
    console.log('watchEffect配置的回调执行了')
})

⑧ life cycle

insert image description here

1. The lifecycle hooks in Vue2.x can continue to be used in Vue3.0, but two of them have been renamed:

  • beforeDestroy was renamed to beforeUnmount
  • destroyed changed its name to unmounted

Lifecycle hooks can be used directly in the form of configured items, or in the form of combined APIs, as uniform as possible. Generally speaking, the hooks in the combined API will be executed before the hooks of the configuration items. The name of the hook in the combined API Change

2. Vue3.0 also provides a lifecycle hook in the form of Composition API, which corresponds to the hook in Vue2.x as follows:
Composition API is to introduce the APIs that need to be used uniformly and then call them in setup()

  • beforeCreate===>setup()
  • created=======>setup()
  • beforeMount ===>onBeforeMount
  • mounted=======>onMounted
  • beforeUpdate===>onBeforeUpdate
  • updated =======>onUpdated
  • beforeUnmount ==>onBeforeUnmount
  • unmounted =====>onUnmounted
    insert image description here

⑨ Custom hook function (emphasis)

Preview effect: https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/26b272c72ede43a1acb50937d8e6ef67~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp

  • What are hooks? —— It is essentially a function that encapsulates the Composition API used in the setup function.

  • Similar to mixin in vue2.x.

  • Advantages of custom hooks: code reuse, making the logic in setup clearer and easier to understand.

Create a hooks folder and create files inside/hooks/usePoint.js

import {
    
     reactive, onMounted, onBeforeUnmount } from "vue";
export default function() {
    
    
  //实现鼠标“打点”相关的数据
  let point = reactive({
    
    
    x: 0,
    y: 0,
  });


  //实现鼠标“打点”相关的方法
  function savePoint(event) {
    
    
    point.x = event.pageX;
    point.y = event.pageY;
    console.log(event.pageX, event.pageY);
  }

  //实现鼠标“打点”相关的生命周期钩子
  onMounted(() => {
    
    
    window.addEventListener("click", savePoint);
  });

  onBeforeUnmount(() => {
    
    
    window.removeEventListener("click", savePoint);
  });

  return point;
}

used in components

<template>
	<h2>我是HelloWorld组件</h2>
	<h2>当前点击时鼠标的坐标为:x:{
    
    {
    
    point.x}},y:{
    
    {
    
    point.y}}</h2>
</template>

<script>
	import usePoint from '../hooks/usePoint'
	export default {
    
    
		name:'HelloWorld',
		setup(){
    
    
			const point = usePoint()
			return {
    
    point}
		}
	}
</script>

⑩ toRef

1. Function:

Creates a ref object whose value points to a property in another object.

2. Grammar:
const name = toRef(person,'name')
3. Application:

When you want to provide a property in the reactive object for external use alone.

4. Expansion:

toRefsConsistent with toRefthe function, but multiple ref objects can be created in batches, syntax:toRefs(person)

<template>
	<h4>{
    
    {
    
    person}}</h4>
	<h2>姓名:{
    
    {
    
    name}}</h2>
	<h2>年龄:{
    
    {
    
    age}}</h2>
	<h2>薪资:{
    
    {
    
    job.j1.salary}}K</h2>
	<button @click="name+='~'">修改姓名</button>
	<button @click="age++">增长年龄</button>
	<button @click="job.j1.salary++">涨薪</button>
</template>

<script>
	import {
    
    ref,reactive,toRef,toRefs} from 'vue'
	export default {
    
    
		name: 'Demo',
		setup(){
    
    
			//数据
			let person = reactive({
    
    
				name:'张三',
				age:18,
				job:{
    
    
					j1:{
    
    
						salary:20
					}
				}
			})

			// const name1 = person.name
			// console.log('%%%',name1)

			// const name2 = toRef(person,'name')
			// console.log('####',name2)

			const x = toRefs(person)
			console.log('******',x)

			return {
    
    
				person,
				// name:toRef(person,'name'),
				// age:toRef(person,'age'),
				// salary:toRef(person.job.j1,'salary'),
				...toRefs(person)
			}
		}
	}
</script>

5. Other Composition APIs

1. shallowReactive 与 shallowRef

  1. shallowReactive: only handles the response (shallow response) of the outermost properties of the object.

  2. shallowRef: only handles the response of basic data types, not the response of objects.

  • When to use it?
    • If there is an object data, the structure is relatively deep, but only the outer attribute changes ===> shallowReactive.
    • If there is an object data, the subsequent function will not modify the properties in the object, but generate a new object to replace ===> shallowRef.

2. readonly 与 shallowReadonly

  • readonly: Make a reactive data read-only (deep read-only).
  • shallowReadonly: Make a responsive data read-only (shallow read-only), only the data in the first layer can be changed, and the data in the second layer and subsequent data can be changed.
  • Application scenario: When the data is not expected to be modified.

3. toRaw and markRaw

  • toRaw

    • Function: Convert a reactiveresponsive object generated by a bot into a normal object.
    • Usage scenario: It is used to read the common object corresponding to the responsive object. All operations on this common object will not cause page updates.
  • markRaw

    • Role: Mark an object so that it will never become a responsive object again.
      Application scenario:

      • Some values ​​should not be set responsive, such as complex third-party libraries, etc.
      • Skipping reactive transformations can improve performance when rendering large lists with immutable data sources.

4. customRef

Role: Create a custom ref with explicit control over its dependency tracking and update triggering.

Achieve anti-shake effect

<template>
  <input type="text" v-model="keyWord" />
  <h3>{
    
    {
    
     keyWord }}</h3>
</template>

<script>
import {
    
     customRef } from "vue";
export default {
    
    
  name: "App",
  setup() {
    
    
    //自定义一个ref——名为:myRef
    function myRef(value, delay) {
    
    
      let timer;
      // track, trigger相符相成,在get、set中结合使用
      return customRef((track, trigger) => {
    
    
        return {
    
    
          get() {
    
    
            console.log(`有人从myRef这个容器中读取数据了,我把${
     
     value}给他了`);
            track(); // 通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
            return value;
          },
          set(newValue) {
    
    
            console.log(`有人把myRef这个容器中数据改为了:${
     
     newValue}`);
            clearTimeout(timer);
            timer = setTimeout(() => {
    
    
              value = newValue;
              trigger(); // 通知Vue去重新解析模板
            }, delay);
          },
        };
      });
    }

    // let keyWord = ref('hello') //使用Vue提供的ref
    let keyWord = myRef("hello", 500); //使用程序员自定义的ref

    return {
    
     keyWord };
  },
};
</script>

5. providewithinject

insert image description here

  • Role: Realize communication between ancestor and descendant components

  • Routine: the parent component has an provideoption to provide data, and the descendant components have an injectoption to start using this data

  • Specifically written:

    1. In the parent component:
      insert image description here

      
      setup(){
              
              
      	......
          let car = reactive({
              
              name:'奔驰',price:'40万'})
          provide('car',car) // 给自己的后代组件传递数据
          ......
      }
      
    2. In descendant components:
      insert image description here

      setup(props,context){
              
              
      	......
          const car = inject('car') // 拿到祖先的数据
          return {
              
              car}
      	......
      }
      

6. Judgment of responsive data

  • isRef: checks if a value is a refobject
  • isReactive: checks if an object was reactivecreated by a reactive proxy
  • isReadonly: checks if an object was readonlycreated by a read-only proxy
  • isProxy: Checks if an object is a proxy created by the reactiveor methodreadonly

The introduction of the Composition API is almost over. Go back and look at the animation at this time, and you will feel that Vue3 is really fragrant!

6. New components

1. Fragment

In Vue2: the component must have a root tag
In Vue3: the component can have no root tag, and multiple tags will be included in a Fragment virtual element internally.
Benefits: Reduce tag levels and reduce memory usage

2. Teleport

What is Teleport? —— Teleport is a technology that can move our component html structure to a specified location.

<teleport to="移动位置">
	<div v-if="isShow" class="mask">
		<div class="dialog">
			<h3>我是一个弹窗</h3>
			<button @click="isShow = false">关闭弹窗</button>
		</div>
	</div>
</teleport>

Let’s take a pop-up window component as an example
Let’s create a nested box, and then set the pop-up window in the innermost box
insert image description here
insert image description here

App parent component


<template>
  <div class="app">
    <h3>我是App组件</h3>
    <Child />
  </div>
</template>

<script>
import Child from "./components/Child";
export default {
    
    
  name: "App",
  components: {
    
     Child },
};
</script>

<style>
.app {
    
    
  background-color: gray;
  padding: 10px;
}
</style>

Child son component


<template>
  <div class="child">
    <h3>我是Child组件</h3>
    <Son />
  </div>
</template>

<script>
import Son from "./Son";
export default {
    
    
  name: "Child",
  components: {
    
     Son },
};
</script>

<style>
.child {
    
    
  background-color: skyblue;
  padding: 10px;
}
</style>

Son grandchild component


<template>
  <div class="son">
    <h3>我是Son组件</h3>
    <Dialog />
  </div>
</template>

<script>
import Dialog from "./Dialog.vue";
export default {
    
    
  name: "Son",
  components: {
    
     Dialog },
};
</script>

<style>
.son {
    
    
  position: relative;
  background-color: orange;
  padding: 10px;
}
</style>

Dialog covered by Dialog


<template>
  <div>
    <button @click="isShow = true">点我弹个窗</button>
    <div v-if="isShow" class="mask">
      <div class="dialog">
        <h3>我是一个弹窗</h3>
        <h4>一些内容</h4>
        <h4>一些内容</h4>
        <h4>一些内容</h4>
        <button @click="isShow = false">关闭弹窗</button>
      </div>
    </div>
  </div>
</template>

<script>
import {
    
     ref } from "vue";
export default {
    
    
  name: "Dialog",
  setup() {
    
    
    let isShow = ref(false);
    return {
    
     isShow };
  },
};
</script>

<style>
.mask {
    
    
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: rgba(0, 0, 0, 0.5);
}
.dialog {
    
    
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  width: 300px;
  height: 300px;
  background-color: green;
}
</style>

I deliberately added positioning to the innermost box, because relative positioning will find the nearest positioning box on the outer layer for positioning, so the effect is like this, we hope that this pop-up window is presented under the body

We add a teleport tag to the Dialog component

<template>
  <div>
    <button @click="isShow = true">点我弹个窗</button>
    <teleport to="body">
    <div v-if="isShow" class="mask">
      <div class="dialog">
        <h3>我是一个弹窗</h3>
        <h4>一些内容</h4>
        <h4>一些内容</h4>
        <h4>一些内容</h4>
        <button @click="isShow = false">关闭弹窗</button>
      </div>
    </div>
    </teleport>
  </div>
</template>

that's good

3. Suspense

  • Render some extra content while waiting for asynchronous components, so that the application has a better user experience

  • Steps for usage:

    • Import components asynchronously (dynamic import)
    import {
          
          defineAsyncComponent} from 'vue'
    const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
    
    • Use Suspensethe package component and configure it defaultwithfallback
    <template>
    	<div class="app">
    		<h3>我是App组件</h3>
    		<Suspense>
    			<template v-slot:default>
    				<Child/>
    			</template>
    			<template v-slot:fallback>
    				<h3>加载中.....</h3>
    			</template>
    		</Suspense>
    	</div>
    </template>
    

default: It is the content to be displayed by the component
fallback: It is the "spare tire" that the component is not fully loaded

7. Others

1. Transfer of global API

Vue 2.x has many global APIs and configurations.

  • For example: registering global components, registering global directives, etc.
//注册全局组件
Vue.component('MyButton', {
    
    
  data: () => ({
    
    
    count: 0
  }),
  template: '<button @click="count++">Clicked {
    
    { count }} times.</button>'
})
//注册全局指令
Vue.directive('focus', {
    
    
  inserted: el => el.focus()
}

These APIs have been adjusted in Vue3.0:

  • Adjust the global API, namely: Vue.xxx to the application (app)instance
    insert image description here

insert image description here

2. Other changes

① The data option should always be declared as a function
② Change of transition class name
  • Vue2.x writing method
.v-enter,
.v-leave-to {
    
    
  opacity: 0;
}
.v-leave,
.v-enter-to {
    
    
  opacity: 1;
}
  • Vue3.x writing method

.v-enter-from,
.v-leave-to {
    
    
  opacity: 0;
}

.v-leave-from,
.v-enter-to {
    
    
  opacity: 1;
}
③ Remove keyCode as a v-on modifier, and no longer support config.keyCodes
④ Remove the v-on.native modifier
  • Bind event in parent component
<my-component
  v-on:close="handleComponentEvent"
  v-on:click="handleNativeClickEvent"
/>
  • Declare custom events in subcomponents
<script>
  export default {
    
    
    emits: ['close']
  }
</script>
⑤ Remove the filter (filter)

Filters While this seems convenient, it requires a custom syntax that breaks the assumption that expressions inside curly braces are "just JavaScript", which has not only a learning cost, but an implementation cost as well! It is recommended to replace filters with method calls or computed properties.

reference

Vue3 official document v3.cn.vuejs.org /
Vite official document cn.vitejs.dev/
Vue-cli official document cli.vuejs.org/zh/
Shang Silicon Valley Vue3 video www.bilibili.com/video/BV1Zy…

Guess you like

Origin blog.csdn.net/qq_53810245/article/details/131380190