Vue3 的 15 个常用 API

Souleigh ✨
• 阅读 1471

来自公众号:前端印象

本文会频繁地对比Vue2来介绍Vue3,也将对各个API结合代码实例讲解,这既是对自己知识的总结,也希望能帮助到大家

一、前言

大家都知道,现在Vue3的各个版本已经陆续发布了,并且有很多的团队已经着手各个库的开发与Vue2向Vue3的升级,我们当然也不能落后,所以赶紧将你手中的Vue2升级到Vue3,跟着本文一起学习新的API吧

二、正文

Vue2每次都把整个Vue导入,例如Vue2的 main.js 文件中的代码

import App from './App.vue'  

Vue.config.productionTip = false  

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

但很明显我们的项目中不可能用到Vue所有的API,因此很多模块其实是没有用的

那么在Vue3中,对外暴露了很多的API供开发者使用,我们可以根据自己的需求,将所需要的API从Vue中导入。例如 main.js 中的代码

import App from './App.vue'  

createApp(App).mount('#app')  

利用了 importexport 的导入导出语法,实现了按需打包模块的功能,项目打包后的文件体积明显小了很多

这也是我们本文需要对 Vue3 API 进行详细了解的原因

(1)setup

setup 函数也是 Composition API 的入口函数,我们的变量、方法都是在该函数里定义的,来看一下使用方法

  <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>  

上述代码中用到了 ref 函数,下面会详细讲解,在这里你只需要理解它的作用是包装一个响应式的数据即可,并且你可以将 ref 函数包装过的变量看作是Vue2 data 中的变量

这样就简单实现了一个点击按钮数字加1的功能


在Vue2中,我们访问 dataprops 中的变量,都是通过类似 this.number 这样的形式去获取的,但要特别注意的是,在setup中,this 指向的是 undefined,也就是说不能再向Vue2一样通过 this 去获取变量了

那么到底该如何获取到 props 中的数据呢?

其实 setup 函数还有两个参数,分别是 propscontext,前者存储着定义当前组件允许外界传递过来的参数名称以及对应的值;后者是一个上下文对象,能从中访问到 attremitslots

其中 emit 就是我们熟悉的Vue2中与父组件通信的方法,可以直接拿来调用

(2)生命周期

Vue2中有 beforeCreatecreatedbeforeMountmountedbeforeUpdate 等生命周期函数

而在Vue3中,这些生命周期部分有所变化,并且调用的方式也有所改变,下面放上一张变化图来简单了解一下

Vue2 Vue3
beforeCreate setup
created setup
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestory onBeforeUnmount
destoryed onUnmounted

Vue3的这些生命周期调用也很简单,同样是先从 vue 中导入,再进行直接调用

  <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>  

要特别说明一下的就是,setup 函数代替了 beforeCreatecreated 两个生命周期函数,因此我们可以认为它的执行时间在beforeCreatecreated 之间

(3)reactive

reactive 方法是用来创建一个响应式的数据对象,该API也很好地解决了Vue2通过 defineProperty 实现数据响应式的缺陷

用法很简单,只需将数据作为参数传入即可,代码如下

  <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

在介绍 setup 函数时,我们使用了 ref 函数包装了一个响应式的数据对象,这里表面上看上去跟 reactive 好像功能一模一样啊,确实差不多,因为 ref 就是通过 reactive 包装了一个对象 ,然后是将值传给该对象中的 value 属性,这也就解释了为什么每次访问时我们都需要加上 .value

我们可以简单地把 ref(obj) 理解为这个样子 reactive({value: obj})

这里我们写一段代码来具体看一下

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>  

来看一下打印结果

Vue3 的 15 个常用 API

注意: 这里指的 .value 是在 setup 函数中访问 ref 包装后的对象时才需要加的,在 template 模板中访问时是不需要的,因为在编译时,会自动识别其是否为 ref 包装过的

那么我们到底该如何选择 refreactive 呢?

建议:

  1. 基本类型值(StringNmuberBoolean 等)或单值对象(类似像 {count: 3} 这样只有一个属性值的对象)使用 ref

  2. 引用类型值(ObjectArray)使用 reactive

(5)toRef

toRef 是将某个对象中的某个值转化为响应式数据,其接收两个参数,第一个参数为 obj 对象;第二个参数为对象中的属性名

代码如下:

// 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>  

但其实表面上看上去 toRef 这个API好像非常的没用,因为这个功能也可以用 ref 实现,代码如下

// 1. 导入 ref  
import {ref} from 'vue'  
export default {  
    setup() {  
        const obj = {count: 3}  
        // 2. 将 obj 对象中属性count的值转化为响应式数据  
        const state = ref(obj.count)  

        // 3. 将ref包装过的数据对象返回供template使用  
        return {state}  
    }  
}  
</script>  

乍一看好像还真是,其实这两者是有区别的,我们可以通过一个案例来比较一下,代码如下

    <p>{{ state1 }}</p>  
    <button @click="add1">增加</button>  

 <p>{{ state2 }}</p>  
    <button @click="add2">增加</button>  
</template>  

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

        function add1() {  
            state1.value ++  
            console.log('原始值:', obj);  
            console.log('响应式数据对象:', state1);  
        }  

        function add2() {  
            state2.value ++  
            console.log('原始值:', obj);  
            console.log('响应式数据对象:', state2);  
        }  

        return {state1, state2, add1, add2}  
    }  
}  
</script>  

我们分别用 reftoRefobj 中的 count 转化为响应式,并声明了两个方法分别使 count 值增加,每次增加后打印一下原始值 obj 和被包装过的响应式数据对象,同时还要看看视图的变化

ref:

Vue3 的 15 个常用 API

可以看到,在对响应式数据的值进行 +1 操作后,视图改变了,原始值未改变,响应式数据对象的值也改变了,这说明 ref 是对原数据的一个拷贝,不会影响到原始值,同时响应式数据对象值改变后会同步更新视图

toRef:

Vue3 的 15 个常用 API

可以看到,在对响应式数据的值进行 +1 操作后,视图未发生改变,原始值改变了,响应式数据对象的值也改变了,这说明 toRef 是对原数据的一个引用,会影响到原始值,但是响应式数据对象值改变后会不会更新视图

总结:

  1. ref 是对传入数据的拷贝;toRef 是对传入数据的引用

  2. ref 的值改变会更新视图;toRef 的值改变不会更新视图

(6)toRefs

了解完 toRef 后,就很好理解 toRefs 了,其作用就是将传入的对象里所有的属性的值都转化为响应式数据对象,该函数支持一个参数,即 obj 对象

我们来看一下它的基本使用

// 1. 导入 toRefs  
import {toRefs} from 'vue'  
export default {  
    setup() {  
        const obj = {  
          name: '前端印象',  
          age: 22,  
          gender: 0  
        }  
        // 2. 将 obj 对象中属性count的值转化为响应式数据  
        const state = toRefs(obj)  

        // 3. 打印查看一下  
        console.log(state)  
    }  
}  
</script>  

打印结果如下:

Vue3 的 15 个常用 API

返回的是一个对象,对象里包含了每一个包装过后的响应式数据对象

(7)shallowReactive

听这个API的名称就知道,这是一个浅层的 reactive,难道意思就是原本的 reactive 是深层的呗,没错,这是一个用于性能优化的API

其实将 obj 作为参数传递给 reactive 生成响应式数据对象时,若 obj 的层级不止一层,那么会将每一层都用 Proxy 包装一次,我们来验证一下

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>  

来看一下打印结果:

Vue3 的 15 个常用 API

设想一下如果一个对象层级比较深,那么每一层都用 Proxy 包装后,对于性能是非常不友好的

接下来我们再来看看 shallowReactive

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>  

来看一下打印结果:

Vue3 的 15 个常用 API

结果非常的明了了,只有第一层被 Proxy 处理了,也就是说只有修改第一层的值时,才会响应式更新,代码如下:

 <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}  
    }  
}  
</script>  

来看一下具体过程:

Vue3 的 15 个常用 API

首先我们点击了第二个按钮,改变了第二层的 b 和第三层的 c,虽然值发生了改变,但是视图却没有进行更新;

当我们点击了第一个按钮,改变了第一层的 a 时,整个视图进行了更新;

由此可说明,shallowReactive 监听了第一层属性的值,一旦发生改变,则更新视图

(8)shallowRef

这是一个浅层的 ref,与 shallowReactive 一样是拿来做性能优化的

shallowReactive 是监听对象第一层的数据变化用于驱动视图更新,那么 shallowRef 则是监听 .value 的值的变化来更新视图的

我们来看一下具体代码

 <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>  

首先看一下被 shallowRef 包装过后是怎样的结构

Vue3 的 15 个常用 API

然后再来看看改变其值会有什么变化

Vue3 的 15 个常用 API

我们先点击了第二个按钮,发现数据确实被改变了,但是视图并没随之更新;

于是点击了第一个按钮,即将整个 .value 重新赋值了,视图就立马更新了

这么一看,未免也太过麻烦了,改个数据还要重新赋值,不要担心,此时我们可以用到另一个API,叫做 triggerRef ,调用它就可以立马更新视图,其接收一个参数 state ,即需要更新的 ref 对象

我们来使用一下

 <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>  

我们来看一下具体过程

Vue3 的 15 个常用 API

可以看到,我们没有给 .value 重新赋值,只是在修改值后,调用了 triggerRef 就实现了视图的更新

(9)toRaw

toRaw 方法是用于获取 refreactive 对象的原始数据的

先来看一段代码

 <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>  

来看看具体过程

Vue3 的 15 个常用 API

我们改变了 reactive 对象中的数据,于是看到原始数据 obj 和被 reactive 包装过的对象的值都发生了变化,由此我们可以看出,这两者是一个引用关系

那么此时我们就想了,那如果直接改变原始数据 obj 的值,会怎么样呢?答案是:reactive 的值也会跟着改变,但是视图不会更新

由此可见,当我们想修改数据,但不想让视图更新时,可以选择直接修改原始数据上的值,因此需要先获取到原始数据,我们可以使用 Vue3 提供的 toRaw 方法

toRaw 接收一个参数,即 ref 对象或 reactive 对象

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>  

上述代码就证明了 toRaw 方法从 reactive 对象中获取到的是原始数据,因此我们就可以很方便的通过修改原始数据的值而不更新视图来做一些性能优化了

注意: 补充一句,当 toRaw 方法接收的参数是 ref 对象时,需要加上 .value 才能获取到原始数据对象

(10)markRaw

markRaw 方法可以将原始数据标记为非响应式的,即使用 refreactive 将其包装,仍无法实现数据响应式,其接收一个参数,即原始数据,并返回被标记后的数据

我们来看一下代码

 <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>  

我们来看一下在被 markRaw 方法处理过后的数据是否还能被 reactive 包装成响应式数据

Vue3 的 15 个常用 API

从图中可以看到,即使我们修改了值也不会更新视图了,即没有实现数据响应式

(11)provide && inject

与 Vue2中的 provideinject 作用相同,只不过在Vue3中需要手动从 vue 中导入

这里简单说明一下这两个方法的作用:

  • provide :向子组件以及子孙组件传递数据。接收两个参数,第一个参数是 key,即数据的名称;第二个参数为 value,即数据的值

  • inject :接收父组件或祖先组件传递过来的数据。接收一个参数 key,即父组件或祖先组件传递的数据名称

假设这有三个组件,分别是 A.vueB.vueC.vue,其中 B.vueA.vue 的子组件,C.vueB.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

watchwatchEffect 都是用来监视某项数据变化从而执行指定的操作的,但用法上还是有所区别

watch:watch( source, cb, [options] )

参数说明:

  • source:可以是表达式或函数,用于指定监听的依赖对象

  • cb:依赖对象变化后执行的回调函数

  • options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)

当监听 ref 类型时:

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>  

当监听 reactive 类型时:

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>  

当同时监听多个值时:

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>  

因为 watch 方法的第一个参数我们已经指定了监听的对象,因此当组件初始化时,不会执行第二个参数中的回调函数,若我们想让其初始化时就先执行一遍,可以在第三个参数对象中设置 immediate: true

watch 方法默认是渐层的监听我们指定的数据,例如如果监听的数据有多层嵌套,深层的数据变化不会触发监听的回调,若我们想要其对深层数据也进行监听,可以在第三个参数对象中设置 deep: true

补充: watch方法会返回一个stop方法,若想要停止监听,便可直接执行该stop函数

接下来再来聊聊 watchEffect,它与 watch 的区别主要有以下几点:

  1. 不需要手动传入依赖

  2. 每次初始化时会执行一次回调函数来自动获取依赖

  3. 无法获取到原值,只能得到变化后的值

来看一下该方法如何使用:

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

          watchEffect(() => {  
          console.log(state.count)  
          console.log(state.name)  
          /*  初始化时打印:  
                  0  
                  zs  

            1秒后打印:  
                  1  
                  ls  
          */  
          })  

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

从上述代码中可以看出,我们并没有像 watch 方法一样先给其传入一个依赖,而是直接指定了一个回调函数

当组件初始化时,将该回调函数执行一次,自动获取到需要检测的数据是 state.countstate.name

根据以上特征,我们可以自行选择使用哪一个监听器

(13)getCurrentInstance

我们都知道在Vue2的任何一个组件中想要获取当前组件的实例可以通过 this 来得到,而在Vue3中我们大量的代码都在 setup 函数中运行,并且在该函数中 this 指向的是 undefined,那么该如何获取到当前组件的实例呢?

这时可以用到另一个方法,即 getCurrentInstance

 <p>{{ num }}</p>  
</template>  
<script>  
import {ref, getCurrentInstance} from 'vue'  
export default {  
    setup() {   
        const num = ref(3)  
        const instance = getCurrentInstance()  
        console.log(instance)  

        return {num}  
    }  
}  
</script>  

我们来看一下其打印结果

Vue3 的 15 个常用 API

因为 instance 包含的内容太多,所以没截完整,但是主要的内容都在图上了,我们重点来看一下 ctxproxy,因为这两个才是我们想要的 this 的内容

Vue3 的 15 个常用 API)Vue3 的 15 个常用 API

可以看到 ctxproxy 的内容十分类似,只是后者相对于前者外部包装了一层 proxy,由此可说明 proxy 是响应式的

(14)useStore

在Vue2中使用 Vuex,我们都是通过 this.$store 来与获取到Vuex实例,但上一部分说了原本Vue2中的 this 的获取方式不一样了,并且我们在Vue3的 getCurrentInstance().ctx 中也没有发现 $store 这个属性,那么如何获取到Vuex实例呢?这就要通过 vuex 中的一个方法了,即 useStore

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>  

我们来看一下打印结果

Vue3 的 15 个常用 API

然后接下来就可以像之前一样正常使用 vuex

(15)获取标签元素

最后再补充一个 ref 另外的作用,那就是可以获取到标签元素或组件

在Vue2中,我们获取元素都是通过给元素一个 ref 属性,然后通过 this.$refs.xx 来访问的,但这在Vue3中已经不再适用了

接下来看看Vue3中是如何获取元素的吧

  <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>  

获取元素的操作一共分为以下几个步骤:

  1. 先给目标元素的 ref 属性设置一个值,假设为 el

  2. 然后在 setup 函数中调用 ref 函数,值为 null,并赋值给变量 el,这里要注意,该变量名必须与我们给元素设置的 ref 属性名相同

  3. 把对元素的引用变量 el 返回(return)出去

补充:设置的元素引用变量只有在组件挂载后才能访问到,因此在挂载前对元素进行操作都是无效的

当然如果我们引用的是一个组件元素,那么获得的将是该组件的实例对象,这里就不做过多的演示了

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
京东云开发者 京东云开发者
5个月前
Vue3设计思想及响应式源码剖析 | 京东物流技术团队
一、Vue3结构分析1、Vue2与Vue3的对比对TypeScript支持不友好(所有属性都放在了this对象上,难以推倒组件的数据类型)大量的API挂载在Vue对象的原型上,难以实现TreeShaking。架构层面对跨平台dom渲染开发支持不友好,vue
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这