Skip to content

ref 模板引用

在项目开发中,如果要获取并操作 DOM 元素,除了调用原生的 DOM API 之外,还可以使用 vue 提供的 ref 属性来引用页面上的元素。语法如下:

html
<input ref="ipt" />

基本语法

  1. 创建 ref 引用:

    js
    setup() {
      // 声明一个 ref 来存放该元素的引用
      // 必须和模板里的 ref 同名
      const ipt = ref(null)
    
      return {
        // 在 setup() 中必须返回 ref 引用,才能在模板中使用 ref 引用
        ipt
      }
    }
  2. 为模板中的元素绑定 ref 属性,属性值为元素引用的名称

    html
    <div id="app">
      <input type="text" ref="ipt" />
      <button @click="iptGetFocus">文本框获取焦点</button>
    </div>
  3. 通过 .value 访问 ref 所引用的页面元素:

    js
    setup() {
      const ipt = ref(null)
    
      // 在点击按钮之后,让文本框获得焦点
      const iptGetFocus = () => ipt.value.focus()
    
      return {
        ipt,
        iptGetFocus
      }
    }

v-for 中的模板引用

当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素:

js
setup() {
  // 列表数据
  const list = ref([
    { id: 1, name: '关羽' },
    { id: 2, name: '张飞' },
    { id: 3, name: '马超' },
    { id: 4, name: '赵云' },
    { id: 5, name: '黄忠' }
  ])

  // 存放 DOM 引用的 ref 数组
  const rowsRef = ref([])

  // 按钮的点击事件处理函数,循环设置奇偶行背景色
  const toggleRowColor = () => {
    rowsRef.value.forEach((item, i) => {
      const color = i % 2 === 0 ? 'lightgreen' : 'orange'
      item.style.backgroundColor = color
    })
  }

  return {
    list,
    toggleRowColor,
    rowsRef
  }
}
html
<ul>
  <!-- 在 v-for 上使用 ref 时,获取到的是 DOM 元素的数组 -->
  <li v-for="item in list" :key="item.id" ref="rowsRef">{{item.name}}</li>
</ul>
<button @click="toggleRowColor">设置奇偶行颜色</button>

函数模板引用

除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:

html
<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }" />

注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时函数也会被调用一次,此时的 el 参数会是 null。你当然也可以绑定一个组件方法而不是内联函数。

ref 函数的执行时机

  1. 页面首次渲染时执行
  2. 页面更新渲染时执行
  3. 绑定的元素被卸载时执行

示例代码:

js
setup() {
  // 布尔值,控制 input 元素的显示和隐藏
  const flag = ref(true)
  // 绑定给 :ref 的函数
  const autoGetFocus = (el) => {
    el?.focus()
  }

  return {
    flag,
    autoGetFocus
  }
}
html
<input type="text" v-if="flag" :ref="autoGetFocus" /> <button @click="flag = !flag">toggle input</button>

天不生夫子,万古长如夜