关于 vue3 模板引用


前言

如果我们需要直接访问组件中的底层DOM元素,可使用vue提供特殊的ref属性来访问


1.访问模板引用

  1. 在视图元素中采用ref属性来设置需要访问的DOM元素
    a. 该ref属性可采用字符值的执行设置
    b. 该ref属性可采用v-bind:或:ref的形式来绑定函数,其函数的第一个参数则为该元素
  2. 如果元素的ref属性值采用的是字符串形式
    a. 在选项式 API JS中,可通过this.$refs来访问模板引用
    b. 在组合式 API JS中,我们需要声明一个同名的ref变量,来获得该模板的引用

访问模板引用【选项式】

<script>
export default {
    
    
    data: () => ({
    
    
        accountEl: null,
        passwordEl: null
    }),
    methods: {
    
    
        changeAccountInputStyle() {
    
    
            this.accountEl = this.$refs.account // 获取账号输入框的 DOM
            console.log(this.accountEl)
            this.accountEl.style = "padding: 15px"
            this.accountEl.className = "rounded"
            this.accountEl.focus()
        },
        passwordRef(el) {
    
     
            this.passwordEl = el  // el 元素是密码输入框
        },
        changePasswordInputStyle() {
    
    
            console.log(this.passwordEl) 
            console.log(this.$refs) // 函数式声明的 ref,不会在this.$refs中获取
            this.passwordEl.style = "padding: 15px"
            this.passwordEl.className = "rounded"
            this.passwordEl.focus()
        },
    }
}
</script>


<template>
    <!-- ref 字符串值形式 -->
   账号输入框:<input type="text" ref="account">
   <button @click="changeAccountInputStyle">改变账号输入框的样式</button>

   <hr>

   <!-- ref 函数形式:元素渲染后,会立即执行该函数 -->
   密码输入框:<input type="password" :ref="passwordRef">
   <button @click="changePasswordInputStyle">改变密码输入框的样式</button>
</template>

<style>
.rounded {
    
    
    border-radius: 15px;
}
</style>

访问模板引用【组合式】

<script setup>
import {
    
     ref } from 'vue';

// 账号输入框
let account = ref(null) // ref 变量名和账号输入框中的 ref 属性值一样

function changeAccountInputStyle() {
    
    
    console.log(account.value)
    account.value.style = 'padding: 10px'
    account.value.className = 'rounded'
    account.value.focus()
}

// ------------------------------------------------------------------------
  
// 密码输入框元素
let passwordEl = ref(null)

function passwordRef(el) {
    
    
    passwordEl.value = el // el 元素是密码输入框
}

function changePasswordInputStyle() {
    
    
    console.log(passwordEl.value)
    passwordEl.value.style = 'padding: 10px'
    passwordEl.value.className = 'rounded'
    passwordEl.value.focus()
}
</script>


<template>
    <!-- ref 字符串值形式 -->
    账号输入框:<input type="text" ref="account">
    <button @click="changeAccountInputStyle">改变账号输入框的样式</button>

    <hr>

    <!-- ref 函数形式:元素渲染后,会立即执行该函数-->
    密码输入框:<input type="password" :ref="passwordRef">
    <button @click="changePasswordInputStyle">改变密码输入框的样式</button>
</template>

<style>
.rounded {
    
    
    border-radius: 15px;
}
</style>

2.v-for中的模板引用

当在v-for中使用模板引用时:

  1. 如果ref值是字符串形式,在元素被渲染后包含对应整个列表的所有元素【数组】
  2. 如果ref值是函数形式,则会每渲染一个列表元素则会执行对应的函数【不推荐使用】

注意:需要v3.2.25及以上版本

列表渲染指令中的模板引用【选项式】

<script>
export default {
    
    
    data: () => ({
    
    
        books: [
            {
    
     id: 1, name: '红楼梦' },
            {
    
     id: 2, name: '三国演义' },
            {
    
     id: 3, name: '水浒传' },
            {
    
     id: 4, name: '西游记' }
        ],
        students: [
            {
    
     id: 1, name: 'Jack' },
            {
    
     id: 2, name: 'Annie' },
            {
    
     id: 3, name: 'Tom' }
        ]
    }),
    methods: {
    
    
        changeBookListStyle() {
    
    
            console.log(this.$refs.bookList)
            this.$refs.bookList[2].style = 'color: red'
        },
        studentsRef(el) {
    
    
            console.log(el)
        }
    }
}
</script>


<template>
    <ul>
        <!-- 如果 ref 值是字符串形式,在元素被渲染后包含对应整个列表的所有元素【数组】 -->
        <li v-for="b in books" :key="b.id" ref="bookList">
            {
    
    {
    
     b.name }}
        </li>
    </ul>
    <button @click="changeBookListStyle">点我查看 bookList </button>

    <hr>
    <!-- 如果ref值是函数形式,则会每渲染一个列表元素则会执行对应的函数【不推荐使用】 -->
    <ul>
        <li v-for="s in students" :key="s.id" :ref="studentsRef">
            {
    
    {
    
     s.name }}
        </li>
    </ul>
</template>

列表渲染指令中的模板引用【组合式】

<script setup>
import {
    
     onMounted, ref } from 'vue';

// 书本
let books = ref([
    {
    
     id: 1, name: '海底两万里' },
    {
    
     id: 2, name: '骆驼祥子' },
    {
    
     id: 3, name: '老人与海' },
    {
    
     id: 4, name: '安徒生童话' },
])

let bookList = ref(null)

onMounted(() => {
    
    
    console.log(bookList.value); // 获取引用的 DOM 对象,并打印,发现那么是数组,
    bookList.value[2].className = 'error'
})
</script>

<template>
    <ul>
        <li v-for="b in books" :key="b.id" ref="bookList">
            {
    
    {
    
     b.name }}
        </li>
    </ul>
</template>

<style>
.error {
    
    
    border: 1px solid red;
}
</style>

3.组件上的ref

模板引用也可以被用在一个子组件上;这种情况下引用中获得的值是组件实例

  1. 如果子组件使用的是选项式 API ,默认情况下父组件可以随意访问该子组件的数据和函数,除非在子组件使用expose选项来暴露特定的数据或函数,expose值为字符串数组
  2. 如果子组件使用的是组合式 API

App.vue【选项式】

<script>
import LoginVue from './components/Login.vue';
export default {
    
    
    components: {
    
     LoginVue },
    data: ()=> ({
    
    
        login_vue: null
    }),
    methods: {
    
    
        showSonData() {
    
    
            console.log(this.login_vue.account) // 访问子组件中的账号数据
            console.log(this.login_vue.password) // 访问子组件中的密码数据
            this.login_vue.toLogin() // 访问子组件中的去登陆函数
        }
    },
    mounted(){
    
    
        this.login_vue = this.$refs.loginView
    }
}
</script>

<template>
    <h3>登陆界面</h3>
    <hr>
    <!-- 组件上的 ref 的值为该组件的实例 -->
    <LoginVue ref="loginView" />
    <hr>

    <button @click="showSonData">查看子组件中的信息</button>
</template>

Login.vue【选项式】

<script>
// 选项式 API ,默认情况下父组件可以随意访问该子组件的数据和函数等
export default {
    
    
    data: ()=> ({
    
    
        account: 'Abc31510',
        password: '123321'
    }),
    methods: {
    
    
        toLogin() {
    
    
            console.log('登录中……');
        }
    },
    // 只暴露指定数据、函数等
    expose: ['account', 'toLogin']
}
</script>

<template>
    账号:<input type="text" v-model="account">
    <br>
    密码:<input type="text" v-model="password">
</template>

猜你喜欢

转载自blog.csdn.net/www61621/article/details/129248462