- Overview
-
早期流行的 JQuery 也是通过操作 DOM 实现
Vue 中更多的是通过数据驱动的方式实现交互,但有时候避免不了仍然需要操作 DOM
通过 ref 标识获取/引用 DOM 节点或组件实例
需引入包 useTemplateRef 再使用;早期版本使用 ref 包
import { useTemplateRef } from 'vue'
- Application
-
焦点管理:当需要自动聚焦到输入框或其它表单元素时
与第三方库交互:例如集成某些需要直接 DOM 节点的 JavaScript 库(如Chart.js)
执行动画:当需要对元素执行复杂的动画效果,而这些效果难以通过 CSS 实现时
文件上传:触发文件选择器等原生控件的操作
测量尺寸:获取元素的宽度、高度等信息用于布局调整
-
直接获取会失败,应在组件 挂载完毕 onMounted 再获取
使用时,应判断是否为空
该属性并不显示在结构中,F12 检查元素时,不可见
- 获取普通 DOM 节点
-
拿到 DOM 节点,就拿到了该元素的所有信息
<script setup>
import { useTemplateRef, onMounted } from 'vue'
let dom = useTemplateRef('null')
onMounted(() => {
console.log(dom);
console.log(dom.value);
console.log(dom.value.innerText);
console.log('nodes', dom.value.childNodes[0]);
console.log('children', dom.value.children[0]);
console.log('classList', dom.value.classList);
console.log('className', dom.value.className);
console.log('style', dom.value.style);
console.log('getAttribute', dom.value.getAttribute('data-ind'));
console.log('getAttribute', dom.value.getAttribute('style'));
console.log('getAttribute', dom.value.getAttribute('class'));
})
</script>
<template>
<div ref="dom"
class="base active"
style="color: #f40;padding: 10px;"
data-ind="100" >
hi,there
<span>88</span>
</div>
</template>
<style scoped></style>
- [] 单击获取焦点、自动聚焦
-
<script setup>
import { useTemplateRef, onMounted } from 'vue';
const ipt = useTemplateRef(null)
const focus = () => ipt.value.focus()
onMounted(() => {
ipt.value.focus()
})
</script>
<template>
<div class="home">
<input type="text" ref="ipt">
<button @click="focus">click for focus</button>
</div>
</template>
- [] 页面/视图滚动到某个位置
- [] 页面滚动时,变换顶部导航样式,如添加阴影
-
为 <header> 指定 ref,在页面加载时使用,并监听页面的滚动事件
页面卸载时,移除事件监听
结构略
import { onMounted, onUnmounted, useTemplateRef } from 'vue'
const header = useTemplateRef(null)
const fn = () => {
header.value.classList.toggle('fixed', window.scrollY > 100)
}
onMounted(() => {
window.addEventListener('scroll', fn)
})
onUnmounted(() => {
window.removeEventListener('scroll', fn)
})
- 获取组件
-
返回组件实例
默认情况下,组件内部的属性和方法对外部不公开,所以获取到的 ref 仅仅是一个代理对象,看不到组件的内部细节
defineExpose 应该写在暴露的对象后面
<template>
<div @click="getTitle">only for test - {{ title }}</div>
</template>
<script setup>
import { ref } from 'vue';
let title = ref(18)
function getTitle() {
console.log(title.value);
}
defineExpose({
title,
getTitle
})
</script>
refs can be useful in certain situations where direct access to a child component's internal state
or methods is necessary.
尽量避免通过 ref 引用组件,请组件的通信机制实现 props 和emit,详见后续组件内容
Remember that accessing a child component's data directly using refs can make your components
tightly coupled. Consider using props and events for communication between components
- [] 自定义搜索组件,单击时,显示并自动获取焦点
-
搜索组件参考设计如下
<script setup>
import { ref, onMounted } from 'vue';
let sql = ref(null)
onMounted(() => {
sql.value.focus()
})
</script>
<template>
<input type="text" ref="sql">
</template>
父组件设计如下
<script setup>
import { ref } from 'vue';
import Search from './components/Search.vue'
let isShow = ref(false)
const showBox = () => {
isShow.value = true
}
</script>
<template>
<button @click="showBox">click</button>
<Search v-if="isShow"></Search>
</template>
- [] 列表渲染
- 思路同事件代理
- [] 单击打开弹窗;更多信息,请访问 实操 - Modal
- 父组件获取子组件|弹窗组件实例,执行弹窗的方法
- 子组件|弹窗组件定义方法并暴露;方法利用 bool 将弹窗组件的隐藏状态变为显示
- 多ref
-
列表渲染中指定 ref,将获取多个元素
必须声明为数组 [] 形式,否则无法遍历
<div v-for="(item,index) in 10" ref="navRef">{{item}}</div>
const navRef = ref([])
onMounted(() => {
navRef.value.forEach(item => {
console.log(item.innerHTML);
})
})
不建议每个子节点都标注 ref 属性
建议获取父节点,再根据节点关系获取子节点