APIs commonly used in vue3

text

Vue2 directly imports the entire Vue, such as the code in Vue2's main.js file:

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    
    
  render: h => h(App)
}).$mount('#app')

And vue3 imports api on demand

import {
    
     createApp } from 'vue';
import App from './App.vue'
createApp(App).mount('#app')

1.setup

The setup function is the entry function of the Composition API. Our variables and methods are defined in this function. Let's see how to use it:

<template>
  <div id="app">
      <p>{
    
    {
    
     number }}</p>
      <button @click="add">增加</button>
  </div>
</template>

<script>
// 1. 从 vue 中引入 ref 函数
import {
    
    ref} from 'vue'
export default {
    
    
  name: 'App',
  setup() {
    
    
      // 2. 用 ref 函数包装一个响应式变量 number
      let number = ref(0)
      // 3. 设定一个方法
      function add() {
    
    
          // number是被ref函数包装过了的,其值保存在.value中
          number.value ++
      }
      // 4. 将 number 和 add 返回出去,供template中使用
      return {
    
    number, add}
  }
}
</script>

The ref function is used in the above code, which will be explained in detail below. Here you only need to understand that its function is to wrap a responsive data, and you can regard the variable wrapped by the ref function as a variable in Vue2 data , so that the function of adding 1 to the number of a click button is simply implemented.

2. Life cycle

<template>
  <div id="app"></div>
</template>
<script>
// 1. 从 vue 中引入 多个生命周期函数
import {
    
    onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted} from 'vue'
export default {
    
    
  name: 'App',
  setup() {
    
    
      onBeforeMount(() => {
    
    
          // 在挂载前执行某些代码
      })

      onMounted(() => {
    
    
          // 在挂载后执行某些代码
      })

      onBeforeUpdate(() => {
    
    
          // 在更新前前执行某些代码
      })

      onUpdated(() => {
    
    
          // 在更新后执行某些代码
      })

      onBeforeUnmount(() => {
    
    
          // 在组件销毁前执行某些代码
      })

      unMounted(() => {
    
    
          // 在组件销毁后执行某些代码
      })

      return {
    
    }
  }
  
}
</script>

3.reactive

The reactive method is used to create a reactive data object.

<template>
  <div id="app">
  	<!-- 4. 访问响应式数据对象中的 count  -->
  	{
    
    {
    
     state.count }}
  </div>
</template>

<script>
// 1. 从 vue 中导入 reactive 
import {
    
    reactive} from 'vue'
export default {
    
    
  name: 'App',
  setup() {
    
    
      // 2. 创建响应式的数据对象
      const state = reactive({
    
    count: 3})
      // 3. 将响应式数据对象state return 出去,供template使用
      return {
    
    state}
  }
}
</script>

4.ref

ref wraps an object through reactive, and then passes the value to the value attribute in the object, which explains why we need to add .value every time we access

<script>
import {
    
    ref, reactive} from 'vue'
export default {
    
    
  name: 'App',
  setup() {
    
    
      const obj = {
    
    count: 3}
      const state1 = ref(obj)
      const state2 = reactive(obj)

      console.log(state1)
      console.log(state2)
  }
}
</script>

Print the result:
insert image description here
Note: The .value referred to here needs to be added only when accessing the object wrapped by ref in the setup function, and it is not needed when accessing in the template template, because it will automatically recognize whether it is a ref when compiling packaged

Choice of ref and reactive:
①.Basic type values ​​(String, Nmuber, Boolean, etc.) or single-value objects (like {count: 3}, objects with only one attribute value) use ref ②Reference type
values ​​(Object, Array) use reactive

5.toRef

toRef converts a value in an object into responsive data. It receives two parameters. The first parameter is the obj object; the second parameter is the attribute name in the object

<script>
// 1. 导入 toRef
import {
    
    toRef} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    count: 3}
        // 2. 将 obj 对象中属性count的值转化为响应式数据
        const state = toRef(obj, 'count')
        // 3. 将toRef包装过的数据对象返回供template使用
        return {
    
    state}
    }
}
</script>

But in fact, the toRef API seems to be very useless on the surface, because this function can also be implemented with ref, the code is as follows:

<script>
// 1. 导入 toRef
import {
    
    toRef} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    count: 3}
        // 2. 将 obj 对象中属性count的值转化为响应式数据
        const state = toRef(obj, 'count')
        // 3. 将toRef包装过的数据对象返回供template使用
        return {
    
    state}
    }
}
</script>

Direct summary instructions:

ref does not change the original value, but updates the view;
toRef changes the original value, but does not update the view

6.toRefs

Its function is to convert the values ​​of all attributes in the incoming object into responsive data objects. This function supports one parameter, namely the obj object

<script>
import {
    
    toRefs} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            name: '前端印象',
            age: 22,
            gender: 0
        }
        const state = toRefs(obj)
        console.log(state)
    }
}
</script>

insert image description here

7.shallowReactive

This is an API for performance optimization.
In fact, when passing obj as a parameter to reactive to generate a responsive data object, if obj has more than one level, each level will be wrapped with Proxy once, let's verify:

<script>
import {
    
    reactive} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            a: 1,
            first: {
    
    
                b: 2,
                second: {
    
    
                    c: 3
                }
            }
        }

        const state = reactive(obj)
        console.log(state)
        console.log(state.first)
        console.log(state.first.second)
    }
}
</script>

insert image description here
Imagine that if an object has a deep hierarchy, each layer is wrapped with Proxy, which is very unfriendly to performance.
Next, let's take a look at shallowReactive:

<script>
import {
    
    shallowReactive} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            a: 1,
            first: {
    
    
                b: 2,
                second: {
    
    
                    c: 3
                }
            }
        }

        const state = shallowReactive(obj)
        console.log(state)
        console.log(state.first)
        console.log(state.first.second)
    }
}
</script>

insert image description here
The result is very clear. Only the first layer is processed by Proxy, that is to say, only when the value of the first layer is modified, will it be updated responsively. The code is as follows:

<template>
	<p>{
    
    {
    
     state.a }}</p>
	<p>{
    
    {
    
     state.first.b }}</p>
	<p>{
    
    {
    
     state.first.second.c }}</p>
	<button @click="change1">改变1</button>
	<button @click="change2">改变2</button>
</template>
<script>
import {
    
    shallowReactive} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            a: 1,
            first: {
    
    
                b: 2,
                second: {
    
    
                    c: 3
                }
            }
        }

        const state = shallowReactive(obj)

        function change1() {
    
    
            state.a = 7
        }

        function change2() {
    
    
            state.first.b = 8
            state.first.second.c = 9
            console.log(state);
        }

        return {
    
    state}
    }
}
// 这里说一下执行结果:
// 首先我们点击了第二个按钮,改变了第二层的 b 和第三层的 c,虽然值发生了改变,但是视图却没有进行更新;
// 当我们点击了第一个按钮,改变了第一层的 a 时,整个视图进行了更新;
// 由此可说明,shallowReactive 监听了第一层属性的值,一旦发生改变,则更新视图。
</script>

8.shallowRef

This is a shallow ref, which is used for performance optimization like shallowReactive.
shallowReactive is to monitor the data change of the first layer of the object to drive the view update, then shallowRef is to monitor the value change of .value to update the view.

<template>
	<p>{
    
    {
    
     state.a }}</p>
	<p>{
    
    {
    
     state.first.b }}</p>
	<p>{
    
    {
    
     state.first.second.c }}</p>
	<button @click="change1">改变1</button>
	<button @click="change2">改变2</button>
</template>

<script>
import {
    
    shallowRef} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            a: 1,
            first: {
    
    
                b: 2,
                second: {
    
    
                    c: 3
                }
            }
        }

        const state = shallowRef(obj)
        console.log(state);

        function change1() {
    
    
            // 直接将state.value重新赋值
            state.value = {
    
    
                a: 7,
                first: {
    
    
                    b: 8,
                    second: {
    
    
                        c: 9
                    }
                }
            }
        }

        function change2() {
    
    
            state.value.first.b = 8
            state.value.first.second.c = 9
            console.log(state);
        }

        return {
    
    state, change1, change2}
    }
}
</script>

The printing result of the state:
insert image description here
We clicked the second button first, and found that the data was indeed changed, but the view was not updated accordingly;
so we clicked the first button, and the entire .value was reassigned, and the view was updated immediately
Looking at it this way, it is too much trouble. If you change the data, you need to reassign the value. Don’t worry, we can use another API called triggerRef at this time. Calling it can update the view immediately, and it receives a parameter state, namely The ref object that needs to be updated
Let's use it:

<template>
	<p>{
    
    {
    
     state.a }}</p>
	<p>{
    
    {
    
     state.first.b }}</p>
	<p>{
    
    {
    
     state.first.second.c }}</p>
	<button @click="change">改变</button>
</template>

<script>
import {
    
    shallowRef, triggerRef} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            a: 1,
            first: {
    
    
                b: 2,
                second: {
    
    
                    c: 3
                }
            }
        }
        const state = shallowRef(obj)
        console.log(state);
        function change() {
    
    
            state.value.first.b = 8
            state.value.first.second.c = 9
            // 修改值后立即驱动视图更新
            triggerRef(state)
            console.log(state);
        }

        return {
    
    state, change}
    }
}
</script>

It can be seen that we did not reassign .value, but just called triggerRef to update the view after modifying the value.

9.toRaw

The toRaw method is used to get the raw data of the ref or reactive object.

<template>
	<p>{
    
    {
    
     state.name }}</p>
	<p>{
    
    {
    
     state.age }}</p>
	<button @click="change">改变</button>
</template>

<script>
import {
    
    reactive} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            name: '前端印象',
            age: 22
        }

        const state = reactive(obj)	

        function change() {
    
    
            state.age = 90
            console.log(obj); // 打印原始数据obj
            console.log(state);  // 打印 reactive对象
        }

        return {
    
    state, change}
    }
}
</script>

insert image description here
We changed the data in the reactive object, so we saw that the values ​​of the original data obj and the object wrapped by reactive have changed, from which we can see that the two are a reference relationship, then we thought at this
time , what happens if the value of the original data obj is changed directly? The answer is: the value of reactive will also change, but the view will not be updated.
It can be seen that when we want to modify the data but do not want the view to be updated, we can choose to directly modify the value on the original data, so we need to get the original data first , we can use the toRaw method
toRaw provided by Vue3 to receive a parameter, that is, a ref object or a reactive object

<script>
import {
    
    reactive, toRaw} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            name: '前端印象',
            age: 22
        }

        const state = reactive(obj)	
        const raw = toRaw(state)

        console.log(obj === raw)   // true
    }
}
</script>

The above code proves that the toRaw method gets the original data from the reactive object, so we can easily do some performance optimization by modifying the value of the original data without updating the view.
Note: Add a sentence, when the parameter received by the toRaw method is a ref object, you need to add .value to get the original data object

10.markRaw

The markRaw method can mark raw data as non-responsive. Even if it is wrapped with ref or reactive, it still cannot achieve data responsiveness. It receives a parameter, that is, raw data, and returns the marked data.

<template>
	<p>{
    
    {
    
     state.name }}</p>
	<p>{
    
    {
    
     state.age }}</p>
	<button @click="change">改变</button>
</template>

<script>
import {
    
    reactive, markRaw} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj = {
    
    
            name: '前端印象',
            age: 22
        }
        // 通过markRaw标记原始数据obj, 使其数据更新不再被追踪
        const raw = markRaw(obj)   
        // 试图用reactive包装raw, 使其变成响应式数据
        const state = reactive(raw)	

        function change() {
    
    
            state.age = 90
            console.log(state);
        }

        return {
    
    state, change}
    }
}
</script>

Let's see if the data processed by the markRaw method can be packaged into responsive data by reactive: As
insert image description here
can be seen from the figure, even if we modify the value, the view will not be updated, that is, data responsiveness is not implemented.

11.provide && inject

Suppose there are three components, namely A.vue, B.vue, and C.vue, where B.vue is a subcomponent of A.vue, and C.vue is a subcomponent of B.vue.

// A.vue
<script>
import {
    
    provide} from 'vue'
export default {
    
    
    setup() {
    
    
        const obj= {
    
    
            name: '前端印象',
            age: 22
        }
        // 向子组件以及子孙组件传递名为info的数据
        provide('info', obj)
    }
}
</script>

// B.vue
<script>
import {
    
    inject} from 'vue'
export default {
    
    
    setup() {
    
    	
        // 接收A.vue传递过来的数据
        inject('info')  // {name: '前端印象', age: 22}
    }
}
</script>

// C.vue
<script>
import {
    
    inject} from 'vue'
export default {
    
    
    setup() {
    
    	
        // 接收A.vue传递过来的数据
        inject('info')  // {name: '前端印象', age: 22}
    }
}
</script>

12.watch && watchEffect

①Monitor ref type:

<script>
import {
    
    ref, watch} from 'vue'
export default {
    
    
    setup() {
    
    	
        const state = ref(0)

        watch(state, (newValue, oldValue) => {
    
    
            console.log(`原值为${
      
      oldValue}`)
            console.log(`新值为${
      
      newValue}`)
            /* 1秒后打印结果:
                            原值为0
                            新值为1
            */
        })

        // 1秒后将state值+1
        setTimeout(() => {
    
    
            state.value ++
        }, 1000)
    }
}
</script>

②Monitor reactive type:

<script>
import {
    
    reactive, watch} from 'vue'
export default {
    
    
    setup() {
    
    	
        const state = reactive({
    
    count: 0})

        watch(() => state.count, (newValue, oldValue) => {
    
    
            console.log(`原值为${
      
      oldValue}`)
            console.log(`新值为${
      
      newValue}`)
            /* 1秒后打印结果:
                            原值为0
                            新值为1
            */
        })

        // 1秒后将state.count的值+1
        setTimeout(() => {
    
    
            state.count ++
        }, 1000)
    }
}
</script>

③Monitor multiple values:

<script>
import {
    
    reactive, watch} from 'vue'
export default {
    
    
    setup() {
    
    	
        const state = reactive({
    
     count: 0, name: 'zs' })

        watch(
            [() => state.count, () => state.name], 
            ([newCount, newName], [oldvCount, oldvName]) => {
    
    
                console.log(oldvCount) // 旧的 count 值
                console.log(newCount) // 新的 count 值
                console.log(oldName) // 旧的 name 值
                console.log(newvName) // 新的 name 值
            }
        )

        setTimeout(() => {
    
    
          state.count ++
          state.name = 'ls'
        }, 1000)
    }
}
</script>

④ Immediate execution and in-depth monitoring

    let sum = ref(0);
    let msg = ref("hello");
    let person = reactive({
    
    
      name: '张三',
      age: 18,
      job: {
    
    
        j1: {
    
    
          salary: 20
        }
      }
    })

	watch([sum,msg], (newVal, oldVal) => {
    
    
      console.log("sum或msg的值变了", "newVal===", newVal, "oldVal===", oldVal);
    },{
    
    immediate: true, ,deep:true});

Supplement: The watch method will return a stop method. If you want to stop monitoring, you can directly execute the stop function

13.getCurrentInstance

Here I directly show the getCurrentInstance used in the project. For example, I want to globally encapsulate an information confirmation prompt box.

The first step is to encapsulate the prompt box component:

/**
 * 信息确定提示框
 */

import {
    
     ElMessageBox } from 'element-plus'
export default function myConfirm(text: string) {
    
    
    return new Promise((resolve, reject) => {
    
    
        ElMessageBox.confirm(text,'系统提示',
            {
    
    
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning',
            }
        ).then(() => {
    
    
            resolve(true)
         })
        .catch(() => {
    
    
            reject(false)
        })
    }).catch(() => {
    
    
        return false
    })
}

The second step is to introduce the tool class in main.ts
insert image description here
The third step is to encapsulate the instance in hooks

import {
    
     getCurrentInstance,ComponentInternalInstance } from "vue";

// 通过 getCurrentInstance 方法获取当前组件实例
export default function userInstance() {
    
    
    const {
    
     proxy, appContext } = getCurrentInstance() as ComponentInternalInstance
    const global = appContext.config.globalProperties
    return {
    
    
        proxy,
        global
    }
}

insert image description here
The fourth step, refer to the example

import userInstance from '@/hooks/userInstance'
export default function userDept(getDeptList,searchParams:ListParam) {
    
    
    const {
    
     global, proxy } = userInstance()
    // 删除
    const deleteBtn = async (id: number) => {
    
    
        // console.log(global)
        // console.log(proxy)
        let params = {
    
     id: id }
        const confirm = await global.$myConfirm('确定删除该数据吗?')
        console.log(confirm)
        if(confirm) {
    
    
            // 执行删除的操作
            let res = await deleteDeptApi(params)
            // console.log(res)
            if(res && res.code === StatusCode.Success) {
    
    
                global.$message({
    
    
                    message: res.msg,
                    type: 'success'
                })
                getDeptList()
            }
        }
    }
    // 保存(更新,新增)
    const saveBtn = async (params: AddDeptModel) => {
    
    
        console.log('父组件取到值了,保存===')
        console.log(params)
        // type: 0新增  1编辑
        let res: Result
        if(params.type === EditType.ADD) {
    
    
            res = await addDeptApi(params)
        } else {
    
    
            res = await editDeptApi(params)
        }
        if(res && res.code === StatusCode.Success) {
    
    
            global.$message({
    
    
                message: res.msg,
                type: 'success'
            })
            // 刷新表格
            getDeptList()
        }
    }

    return {
    
    
        deleteBtn,
        saveBtn
    }
}

Another example, I want to do form validation, how to do it?

Method 1: not recommended

setup() {
    
    
         const {
    
    ctx} = getCurrentInstance();
         console.log(ctx,"属性1")
         
        //表单查询方法
        const submitForm = (formName) =>{
    
    
          ctx.$refs[formName].validate(valid => {
    
    
            if (valid) {
    
    
              ruleForm.pageNum = 1;
              getTableData();
            } else {
    
    
              console.log("error submit!!");
              return false;
            }
          });
        }
}

Method 2: This usage is recommended, so that the official version of your project can run normally and avoid online error reporting.
Solution: Use proxy instead of ctx. Deconstruct the proxy directly in the structure

setup() {
    
    
        let {
    
    proxy} = getCurrentInstance();
        console.log(proxy,"属性2");
         
        //表单查询方法
        const submitForm = (formName) =>{
    
    
          proxy.$refs[formName].validate(valid => {
    
    
            if (valid) {
    
    
              ruleForm.pageNum = 1;
              getTableData();
            } else {
    
    
              console.log("error submit!!");
              return false;
            }
          });
        }
}

14.useStore

// store 文件夹下的 index.js
import Vuex from 'vuex'

const store = Vuex.createStore({
    
    
    state: {
    
    
        name: '前端印象',
        age: 22
    },
    mutations: {
    
    
        ……
    },
    ……
})

// example.vue
<script>
// 从 vuex 中导入 useStore 方法
import {
    
    useStore} from 'vuex'
export default {
    
    
    setup() {
    
    	
        // 获取 vuex 实例
        const store = useStore()

        console.log(store)
    }
}
</script>

15. Get label elements

<template>
  <div>
    <div ref="el">div元素</div>
  </div>
</template>

<script>
import {
    
     ref, onMounted } from 'vue'
export default {
    
    
  setup() {
    
    
      // 创建一个DOM引用,名称必须与元素的ref属性名相同
      const el = ref(null)

      // 在挂载后才能通过 el 获取到目标元素
      onMounted(() => {
    
    
        el.value.innerHTML = '内容被修改'
      })

      // 把创建的引用 return 出去
      return {
    
    el}
  }
}
</script>

Guess you like

Origin blog.csdn.net/weixin_43550562/article/details/126480407