Vue3 study notes

Vue3 study notes

I haven't seen the relevant knowledge of vue3 systematically before. I met the first Spring Festival holiday just more than a month after I joined the job, so I saw the relevant knowledge of vue3 during this period. Otherwise, the project is too hard to do

Vue3 has two ways to create a project

  • Scaffolding

  • Install via vite

What is vite A new generation of front-end building tools (similar to webpack)

Advantages: no packaging, quick start

Initialization project

Attention: the template structure in vue3 build can have no root tag

Common combined api

setup function

A new configuration item in Vue3, whose value is a function

The data and methods used in the component should be configured in setup

Finally, write the variables and functions in setup in return

<template>
  <h1>I am App assembly</h1>
  <h4>full name:{{name}}</h4>
  <h4>Age:{{age}}</h4>
  <button @click="sayHi">sayHi</button>
</template>

<script>

export default {
  name: 'App',
  setup(){
    let name = 'joy';
    let age = 23;
    function sayHi() {
      console.log('Hi')
    };
    return{
    name,
    age,
    sayHi
  }
  },
}
</script>

attention:

  • In Vue2 configuration (data, methods, computed), you can access the properties and methods in setup

  • However, Vue2 configuration (data, methods, computed) cannot be accessed in setup

  • If there are duplicate names, setup takes precedence

async cannot be used to decorate setup because the return value is a promise object and cannot be returned and accessed through return

ref function

ref handles simple types

ref function to convert a variable into a response

<template>
  <h1>Information registration</h1>
  <h4>full name:{{name}}</h4>
  <h4>Age:{{age}}</h4>
  <button @click="changeInfo">One click modification</button>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    let name = ref('joy');
    let age = ref(23);

    function changeInfo() {
      name.value = 'zoey'
      age.value = 18
      // console.log(name,age)
    }

    return{
    name,
    age,
    changeInfo
  }
  },
}
</script>
Ref handles complex types

Basic type of data: the response type still depends on object get and set of defineproperty() are completed

Data of object type: internally, a new function in Vue3 - reactive function is used

<template>
  <h1>Information registration</h1>
  <h4>full name:{{name}}</h4>
  <h4>Age:{{age}}</h4>
  <h4>occupation:{{job.type}}</h4>
  <h4>Salary:{{job.salary}}</h4>
  <button @click="changeInfo">One click modification</button>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    let name = ref('joy');
    let age = ref(23);
    let job = ref({
      type:'Front end development engineer',
      salary:'30K'
    })

    function changeInfo() {
      job.value.type = 'Algorithm Engineer'
      job.value.salary = '50K'
    }

    return{
    name,
    age,
      job,
    changeInfo
  }
  },
}
</script>

reactive function

Handle the response data of object type, and do not use reactive for basic type

reactive defines responsive data as "deep-seated."

The internal Proxy implementation based on ES6 operates the internal data of the source object through the Proxy object

<template>
  <h1>Information registration</h1>
  <h4>full name:{{person.name}}</h4>
  <h4>Age:{{person.age}}</h4>
  <h4>occupation:{{person.job}}</h4>
  <h4>Salary:{{person.salary}}</h4>
  <button @click="changeInfo">One click modification</button>
</template>

<script>
import {reactive} from 'vue'
export default {
  name: 'App',
  setup(){
     const person = reactive({
       name:'joy',
       age : 23,
       job :{
         title:'Front end development engineer',
         salary:'22.5K'
       }
     })

    function changeInfo() {
       person.title = 'Algorithm Engineer',
           person.salary = '50K'
    }

    return{
    person,
    changeInfo
  }
  },
}
</script>

Responsive principle in Vue3

Vue2's responsive principle

Implementation principle:

  • Object type: through object Defineproperty() intercepts the reading and modification of properties (data hijacking)

  • Array type: intercept by rewriting a series of methods to update the array (wrap the change method of the array)

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

Existing problems:

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

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

Vue3's responsive principle

reactive vs ref

  • Compare from the perspective of defining data

    ref is used to define basic type data

    reactive is used to define: object (or array) type data

    attention: ref can also be used to define object (or array) type data, which will be automatically converted into proxy object through reactive

  • Comparison from the perspective of principle

ref through object get and set of defineproperty () to implement responsive (data hijacking)

reactive implements responsive (data hijacking) by using Proxy, and operates the data inside the source object through Reflect

  • From the perspective of use

ref defined data: required for operation data Value, which is not required for direct reading in the template when reading data value

reactive defined data: neither operation data nor read data: required value

Two points for attention in setup

  • Timing of setup execution

Execute once before beforeCreate. this is undefined

  • Parameters of setup

props: the value is an object, including the attributes passed from outside the component and declared and received inside the component

Context: context object

attrs: the value is an object, including: attributes passed from outside the component but not declared in the props configuration

emit: received slot content, equivalent to this$ slots

slots: a function that distributes custom events, equivalent to this$ emit

context

Demo component

<template>
   <h1>A person's information</h1>
   <h4>full name:{{person.name}}</h4>
   <h4>Age:{{person.age}}</h4>
  <button @click="test">Click me to test</button>
</template>

<script>
import {reactive} from "vue";
export default {
  name: "Demo",
  props:{
    name:{
      type:String,
      required:true
    },
    age:{
      type:Number,
      required: true
    }
  },
// Registration event
  emits:['hello'],
  setup(props,context){
    console.log('---context---',context)

    let person = reactive({
      name:'joy',
      age:23
    })

    // methods
    function test(){
    //  Value transfer between components
      context.emit('hello',66)
    }

    return{
      person,
      test
    }
  }
}
</script>

<style scoped>

</style>

App.vue

<template>
  <Demo name="zoey" age=18
  @hello="helloMsg"
  ></Demo>
</template>

<script>
import Demo from "./components/Demo.vue";
export default {
  name: 'App',
  components:{Demo},
  setup(){
    function helloMsg(value){
      alert(`Hello, the parent component has received it Demo Value transfer of ${value}`)
    }

    return{
      helloMsg
    }
  }
}
</script>
slots

Demo component

<template>
   <h1>A person's information</h1>
   <h4>full name:{{person.name}}</h4>
   <h4>Age:{{person.age}}</h4>
  <button @click="test">Click me to test</button>
   <hr>
  <slot name="god">I'm the default</slot>
</template>

<script>
import {reactive} from "vue";
export default {
  name: "Demo",
  props:{
    name:{
      type:String,
      required:true
    },
    age:{
      type:Number,
      required: true
    }
  },
  emits:['hello'],
  setup(props,context){
    // props receive and transmit parameters
    // console.log('---props---',props)

    // emit triggers a custom event
    // console.log('---context---',context.emit)

    // Slot slot
    console.log('---context---',context.slots)

    let person = reactive({
      name:'joy',
      age:23
    })

    // methods
    function test(){
      context.emit('hello',66)
    }

    return{
      person,
      test
    }
  }
}
</script>

<style scoped>

</style>

App.vue

<template>
  <Demo name="zoey" age=18 @hello="helloMsg">
    <template v-slot:god>
      <span>Great God's Road</span>
    </template>
  </Demo>
</template>

<script>
import Demo from "./components/Demo.vue";
export default {
  name: 'App',
  components:{Demo},
  setup(){
    function helloMsg(value){
      alert(`Hello, the parent component has received it Demo Value transfer of ${value}`)
    }

    return{
      helloMsg
    }
  }
}
</script>

Computed calculated properties

The integration becomes the computed() function

When using, it must be referenced first, and the callback function (ordinary function or arrow function) must be written in it

Calculation attribute abbreviation
Calculation attribute write all
<template>
   <h1>A person's information</h1>
   Last name:<input type="text" v-model="person.lastName">
  <br>
   Name:<input type="text" v-model="person.firstName">
  <br>
  full name:<span>{{person.fullName}}</span>
</template>

<script>
import {reactive,computed} from "vue";
export default {
  name: "Demo",

  setup(){
    let person = reactive({
      firstName:'joy',
      lastName:'Zhang'
    })

    // Calculation properties
    // Calculation properties - short form
    // person.fullName = computed(()=>{
    //   return person.firstName + person.lastName
    // })

    person.fullName = computed({
      get(){
        return person.firstName +'-'+ person.lastName
      },
      set(value){
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      }
    })

    return{
      person,
    }
  }
}
</script>

<style scoped>

</style>

watch property

situationI: monitor the responsive data defined by ref

Demo

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
</template>

<script>
import {ref,watch} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
    //watch
    watch(sum,(newValue,oldValue)=>{
      console.log('sum changed',newValue,oldValue)
    })
    return{
      sum
    }
  }
}
</script>

<style scoped>

</style>
situationII: watch monitors changes in multiple ref responsive data

Demo

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
   <h2>Current information is{{msg}}</h2>
  <button @click="msg+='!'">click</button>
</template>

<script>
import {ref,watch} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
    let msg = ref('happy new year')

    watch([sum,msg],(newValue,oldValue)=>{
      console.log('sum/msg changed',newValue,oldValue)
    },{immediate:true})

    return{
      sum,
      msg
    }
  }
}
</script>

<style scoped>

</style>
Situation III: watch listens to the data defined by reactive
  • Unable to get oldValue by listening to data defined by reactive using watch

  • In vue3, no matter how deep the nesting of objects is, as long as it is reactive data defined, use watch to enable deep listening

  • Depth listening is enabled by default and cannot be turned off through {deep:false}

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
  <hr>
   <h2>Current information is{{msg}}</h2>
  <button @click="msg+='!'">click</button>
  <hr>
  <h2>full name:{{person.name}}</h2>
  <h2>Age:{{person.age}}</h2>
  <h2>occupation:{{person.job.job1.title}}</h2>
  <h2>salary:{{person.job.job1.salary}}K</h2>
  <button @click="person.name+='~'">Modify name</button>
  <button @click="person.age++">Growing age</button>
  <button @click="person.job.job1.salary++">Pay rise</button>
</template>

<script>
import {ref,watch,reactive} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
    let msg = ref('happy new year')
    let person = reactive({
      name:'joy',
      age:23,
      job:{
        job1:{
          title:'Front end development engineer',
          salary:30
        }
      }
    })

    watch(person,(newValue,oldValue)=>{
      console.log('person changed',newValue,oldValue)
    },{deep:true})


    return{
      sum,
      msg,
      person
    }
  }
}
</script>

<style scoped>

</style>
Situation IV: watch listens to an attribute in a responsive data defined by reactive

A property of the listening object must be written in the form of the return value of the arrow function, () = > {}

<script>
    watch(()=>person.job.job1.salary,(newValue,oldValue)=>{
      console.log('person changed',newValue,oldValue)
    })
  }
}
</script>
Situation V: watch monitors some attributes in a responsive data defined by reactive
<script>
import {ref,watch,reactive} from "vue";

    watch([()=>person.name,()=>person.age,()=>person.job.job1.salary],(newValue,oldValue)=>{
      console.log('person changed',newValue,oldValue)
    })

</script>
exceptional case

When the monitored data is a deep attribute in an attribute in the reactive responsive data, the deep attribute needs to be added

Situations that cannot be monitored

watch(()=>person.job,(newValue,oldValue)=>{
      console.log('job changed',newValue,oldValue)
    })

After adding deep, it can be monitored

watch(()=>person.job,(newValue,oldValue)=>{
      console.log('job changed',newValue,oldValue)
    },{deep:true})

be careful:

  • When monitoring the reactive data defined by reactive, oldValue failed to get the data correctly and forced to enable deep listening (deep configuration failed)

  • The deep configuration is valid when monitoring an object attribute in the reactive data defined by reactive

watchEffect function

  • watch: indicate both the monitored attribute and the monitored callback

  • watchEffect: it is not necessary to specify which attribute to monitor, and which attribute is used in the monitored callback, so which attribute to monitor

  • watchEffect is a bit like computed:

computed focuses on the calculated value (the return value of the callback function), so the return value must be written

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(()=>{
        // As long as the value is used, automatic monitoring will be enabled
          const x1 = sum.value
          const x2 = person.job.job1.salary
          console.log('watchEffect Triggered')
    })

Life cycle of Vue3

beforeCreate

created

beforeMount

mounted

beforeUpdate

updated

beforeUnmount

unmounted

Demo component

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
</template>

<script>
import {ref,watchEffect,reactive} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)

    return{
      sum,
    }
  },
  beforeCreate() {
    console.log('---beforeCreate---')
  },
  created() {
    console.log('---created---')
  },
  beforeMount() {
    console.log('---beforeMount---')
  },
  mounted() {
    console.log('---mounted---')
  },
  beforeUpdate() {
    console.log('---beforeUpdate---')
  },
  updated() {
    console.log('---updated---')
  },
  beforeUnmount() {
    console.log('---beforeUnmount---')
  },
  unmounted() {
    console.log('---unmounted---')
  }
}
</script>

<style scoped>

</style>

App.vue

<template>
  <Demo v-if="isShowDemo"></Demo>
  <br>
  <br>
  <button @click="isShowDemo = !isShowDemo">Click display/hide</button>
</template>

<script>
import {ref} from 'vue'
import Demo from "./components/Demo.vue";
export default {
  name: 'App',
  components:{Demo},
  setup(){
    let isShowDemo = ref(true)

    return{
      isShowDemo
    }
  }
}
</script>
Life cycle hook function of composite api

Vue3 also provides a life cycle hook in the form of composite api. The corresponding relationship with the hook in Vue2 is as follows:

Note: the way of composite api is to integrate all these life cycle hook functions into setup()

beforeCreated ====> setup()

created ====> setup()

beforeMount =====> onBeforeMount

mounted ====> onMounted

beforeUpdate ====> onBeforeUpdate

updated ====> onUpdated

beforeUnmount ====> onBeforeUnmount

unmounted ====> onUnmounted

Demo component

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
</template>

<script>
import {ref,watchEffect,reactive,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
    console.log('---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---')
    })

    return{sum,}
  },

  // beforeCreate() {
  //   console.log('---beforeCreate---')
  // },
  // created() {
  //   console.log('---created---')
  // },
  // beforeMount() {
  //   console.log('---beforeMount---')
  // },
  // mounted() {
  //   console.log('---mounted---')
  // },
  // beforeUpdate() {
  //   console.log('---beforeUpdate---')
  // },
  // updated() {
  //   console.log('---updated---')
  // },
  // beforeUnmount() {
  //   console.log('---beforeUnmount---')
  // },
  // unmounted() {
  //   console.log('---unmounted---')
  // }
}
</script>

<style scoped>

</style>

attention:

Using the hook function in the composite api, the trigger is faster than the configuration item

Custom hook function

  • What is hook—— It is essentially a function that encapsulates the combinatorial api used in the setup function

  • Similar to mixin in vue2

  • Advantages of custom hook: reuse code to make the logic in setup clearer and easier to understand

Case: click the mouse to obtain the coordinates clicked by the mouse

Demo component

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
  <hr>
  <h2>The current coordinates are x:{{position.x}} y:{{position.y}}</h2>
</template>

<script>
import {ref, reactive, onMounted, onBeforeUnmount} from "vue";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
    let position = reactive({
      x:0,
      y:0
    })

    const getPosition = (e)=>{
     position.x = e.pageX
      position.y =e.pageY
     console.log(e.pageX,e.pageY)
    }

    onMounted(()=>{
      window.addEventListener('click',getPosition)
    })

    onBeforeUnmount(()=>{
      window.removeEventListener('click',getPosition)
    })




    return{sum,position}
  },
}
</script>

<style scoped>

</style>

Using hooks

Create a hooks folder in the src directory, which defines a js file

import {ref, reactive, onMounted, onBeforeUnmount} from "vue";
export function usePosition() {
    let position = reactive({
        x:0,
        y:0
    })

    const getPosition = (e)=>{
        position.x = e.pageX
        position.y =e.pageY
        console.log(e.pageX,e.pageY)
    }

    onMounted(()=>{
        window.addEventListener('click',getPosition)
    })

    onBeforeUnmount(()=>{
        window.removeEventListener('click',getPosition)
    })

//There must be a return value here
    return position
}

In the component, reference hooks, and then use the value to receive the value passed by the function

<template>
   <h2>The current summation is:{{sum}}</h2>
   <button @click="sum++">Point me+1</button>
  <hr>
  <h2>The current coordinates are x:{{position.x}} y:{{position.y}}</h2>
</template>

<script>
import {ref, reactive, onMounted, onBeforeUnmount} from "vue";
import {usePosition} from "../hooks/usePosition";
export default {
  name: "Demo",
  setup(){
   let sum = ref(0)
   const position = usePosition()

    return{sum,position}
  },
}
</script>

<style scoped>

</style>

toRef

Change an attribute in an object into responsive data

Demo component

<template>
  <h2>full name:{{person.name}}</h2>
  <h2>Age:{{person.age}}</h2>
  <h2>occupation:{{person.job.job1.title}}</h2>
  <h2>salary:{{person.job.job1.salary}}K</h2>
  <button @click="person.name+='~'">Modify name</button>
  <br>
  <br>
  <button @click="person.age++">Growing age</button>
  <br>
  <br>
  <button @click="person.job.job1.salary++">Pay rise</button>
  <br>
  <br>
</template>

<script>
import {ref,toRef,reactive} from "vue";
export default {
  name: "Demo",
  setup(){
    let person = reactive({
      name:'joy',
      age:23,
      job:{
        job1:{
          title:'Front end development engineer',
          salary:30
        }
      }
    })



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

<style scoped>

</style>

toRefs

Turn all attributes in an object into responsive data

<template>
  <h2>full name:{{person.name}}</h2>
  <h2>Age:{{person.age}}</h2>
  <h2>occupation:{{person.job.job1.title}}</h2>
  <h2>salary:{{person.job.job1.salary}}K</h2>
  <button @click="person.name+='~'">Modify name</button>
  <br>
  <br>
  <button @click="person.age++">Growing age</button>
  <br>
  <br>
  <button @click="person.job.job1.salary++">Pay rise</button>
  <br>
  <br>
</template>

<script>
import {ref,toRef,reactive,toRefs} from "vue";
export default {
  name: "Demo",
  setup(){
    let person = reactive({
      name:'joy',
      age:23,
      job:{
        job1:{
          title:'Front end development engineer',
          salary:30
        }
      }
    })

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

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

<style scoped>

</style>

Other composite APIs

shallowReactive and shallowRef

readonly and shallowReadonly

toRaw and markRaw

customRef

provide and inject

Judgment of responsive data

isRef: check whether a value is a ref object

isReactive: checks whether an object is a responsive proxy created by reactive

isReadonly: checks whether an object is a read-only proxy created by readonly

isProxy: check whether an object is a proxy created by the reactive or readonly method

<template>
  <Demo v-if="isShowDemo"></Demo>
  <br>
  <br>
  <button @click="isShowDemo = !isShowDemo">Click display/hide</button>
</template>

<script>
import {ref,reactive,readonly,isRef,isReactive,isReadonly,isProxy} from 'vue'
import Demo from "./components/Demo.vue";
export default {
  name: 'App',
  components:{Demo},
  setup(){
    let isShowDemo = ref(true)
    let car = reactive({name:'nio',price:'40w'})
    let carCopy = readonly(car)

    console.log(isRef(isShowDemo)) //true
    console.log(isReactive(car))  //true
    console.log(isProxy(car))   //true
    console.log(isReadonly(carCopy))   //true
     console.log(isProxy(carCopy))   //true
    //readonly is set to read-only and does not change the Proxy attribute of the car

    return{isShowDemo,car,carCopy}
  }
}
</script>

Advantages of Composition api

Problems with the option api

In the traditional option API, to add or modify a requirement, you need to modify it in data, methods and calculated respectively

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-3bnbfkgr-164421795480)( file:///Users/joy.zhang1/Library/Application%20Support/marktext/images/2022 -02-02-11-20-47-image. png)]

Advantages of Composition API

We can organize our code and functions more gracefully. Make the code more organized and relevant

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-fl9kdcq7-164421795481)( file:///Users/joy.zhang1/Library/Application%20Support/marktext/images/2022 -02-02-11-19-48-image. png)]

New components

Fragment

  • In vue2: the component must have a root label

  • In Vue3, components can have no root tag, and multiple tags will be included in a Fragment virtual element

  • Benefits: reduce tag levels and memory usage

Teleport

Suspense

It is still in the experimental stage

other

Keywords: Javascript Front-end Vue Vue.js

Added by frizzo on Mon, 07 Feb 2022 09:10:31 +0200