如果我们需要直接访问组件中的底层DOM元素,可使用vue提供特殊的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>
当在v-for中使用模板引用时:
注意:需要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>
模板引用也可以被用在一个子组件上;这种情况下引用中获得的值是组件实例
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>