x-ref 引用元素 #
什么是 x-ref? #
x-ref 指令用于给 DOM 元素添加引用名称,通过 $refs 魔术属性可以直接访问这些元素。这在需要直接操作 DOM 时非常有用。
基本语法 #
定义引用:
html
<input x-ref="名称">
访问引用:
javascript
this.$refs.名称
基本用法 #
简单引用 #
html
<div x-data>
<input x-ref="emailInput" type="email">
<button @click="$refs.emailInput.focus()">聚焦输入框</button>
</div>
多个引用 #
html
<div x-data>
<input x-ref="name" placeholder="姓名">
<input x-ref="email" placeholder="邮箱">
<input x-ref="phone" placeholder="电话">
<button @click="$refs.name.focus()">聚焦姓名</button>
<button @click="$refs.email.focus()">聚焦邮箱</button>
<button @click="$refs.phone.focus()">聚焦电话</button>
</div>
在方法中使用 #
html
<div x-data="{
focusInput() {
this.$refs.input.focus()
},
clearInput() {
this.$refs.input.value = ''
}
}">
<input x-ref="input" placeholder="输入内容">
<button @click="focusInput()">聚焦</button>
<button @click="clearInput()">清空</button>
</div>
常见用例 #
表单聚焦 #
html
<div x-data="{
showForm: false,
init() {
this.$watch('showForm', (value) => {
if (value) {
this.$nextTick(() => this.$refs.nameInput.focus())
}
})
}
}">
<button @click="showForm = true">显示表单</button>
<form x-show="showForm" @submit.prevent="showForm = false">
<input x-ref="nameInput" placeholder="姓名">
<input placeholder="邮箱">
<button type="submit">提交</button>
</form>
</div>
模态框聚焦 #
html
<div x-data="{
open: false,
showModal() {
this.open = true
this.$nextTick(() => this.$refs.closeButton.focus())
}
}">
<button @click="showModal()">打开模态框</button>
<div x-show="open" class="modal">
<div class="modal-content">
<h2>模态框</h2>
<p>内容</p>
<button x-ref="closeButton" @click="open = false">关闭</button>
</div>
</div>
</div>
文件上传 #
html
<div x-data="{
files: [],
triggerUpload() {
this.$refs.fileInput.click()
},
handleFiles(e) {
this.files = Array.from(e.target.files)
}
}">
<input
x-ref="fileInput"
type="file"
multiple
hidden
@change="handleFiles($event)"
>
<button @click="triggerUpload()">选择文件</button>
<ul>
<template x-for="file in files" :key="file.name">
<li x-text="file.name"></li>
</template>
</ul>
</div>
获取输入值 #
html
<div x-data="{
submit() {
const name = this.$refs.name.value
const email = this.$refs.email.value
console.log({ name, email })
}
}">
<input x-ref="name" placeholder="姓名">
<input x-ref="email" placeholder="邮箱">
<button @click="submit()">提交</button>
</div>
操作 Canvas #
html
<div x-data="{
draw() {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'blue'
ctx.fillRect(10, 10, 100, 100)
},
clear() {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
}">
<canvas x-ref="canvas" width="200" height="200" style="border: 1px solid #ccc"></canvas>
<button @click="draw()">绘制</button>
<button @click="clear()">清除</button>
</div>
滚动控制 #
html
<div x-data="{
scrollToTop() {
this.$refs.container.scrollTop = 0
},
scrollToBottom() {
const el = this.$refs.container
el.scrollTop = el.scrollHeight
}
}">
<div x-ref="container" style="height: 200px; overflow-y: scroll; border: 1px solid #ccc">
<div style="height: 1000px; padding: 20px">
<p>滚动内容区域</p>
<p>...</p>
<p>底部内容</p>
</div>
</div>
<button @click="scrollToTop()">滚动到顶部</button>
<button @click="scrollToBottom()">滚动到底部</button>
</div>
视频控制 #
html
<div x-data="{
play() {
this.$refs.video.play()
},
pause() {
this.$refs.video.pause()
},
stop() {
const video = this.$refs.video
video.pause()
video.currentTime = 0
}
}">
<video x-ref="video" width="320" height="240">
<source src="movie.mp4" type="video/mp4">
</video>
<button @click="play()">播放</button>
<button @click="pause()">暂停</button>
<button @click="stop()">停止</button>
</div>
获取元素尺寸 #
html
<div x-data="{
width: 0,
height: 0,
updateSize() {
const el = this.$refs.box
this.width = el.offsetWidth
this.height = el.offsetHeight
}
}" x-init="updateSize()" @resize.window="updateSize()">
<div x-ref="box" style="width: 200px; height: 100px; background: #f0f0f0">
尺寸: <span x-text="width"></span> x <span x-text="height"></span>
</div>
</div>
复制文本 #
html
<div x-data="{
text: 'Hello World',
copied: false,
async copy() {
const textarea = this.$refs.clipboard
textarea.value = this.text
textarea.select()
await navigator.clipboard.writeText(this.text)
this.copied = true
setTimeout(() => this.copied = false, 2000)
}
}">
<textarea x-ref="clipboard" style="position: absolute; left: -9999px"></textarea>
<input :value="text" readonly>
<button @click="copy()">
<span x-show="!copied">复制</span>
<span x-show="copied">已复制!</span>
</button>
</div>
第三方库集成 #
html
<div x-data="{
editor: null,
init() {
this.editor = new Quill(this.$refs.editor, {
theme: 'snow'
})
},
getContent() {
return this.editor.root.innerHTML
}
}">
<div x-ref="editor"></div>
<button @click="console.log(getContent())">获取内容</button>
</div>
$refs 对象 #
访问方式 #
html
<div x-data>
<input x-ref="input1">
<input x-ref="input2">
<button @click="console.log($refs)">查看所有 refs</button>
<button @click="console.log($refs.input1)">查看 input1</button>
</div>
动态引用 #
html
<div x-data="{
refName: 'input',
focus() {
this.$refs[this.refName].focus()
}
}">
<input x-ref="input" placeholder="输入">
<button @click="focus()">聚焦</button>
</div>
注意事项 #
1. 访问时机 #
$refs 只在组件渲染后可用:
html
<div x-data="{
init() {
console.log(this.$refs.input)
}
}">
<input x-ref="input">
</div>
在 init 中 $refs 可能还未初始化。使用 $nextTick:
html
<div x-data="{
init() {
this.$nextTick(() => {
console.log(this.$refs.input)
})
}
}">
<input x-ref="input">
</div>
2. v-if 影响 #
x-if 会移除元素,$refs 会变为 undefined:
html
<div x-data="{ show: true }">
<template x-if="show">
<input x-ref="input">
</template>
<button @click="console.log($refs.input)">获取 ref</button>
</div>
3. x-show 不影响 #
x-show 只是隐藏元素,$refs 仍然可用:
html
<div x-data="{ show: true }">
<input x-ref="input" x-show="show">
<button @click="console.log($refs.input)">获取 ref</button>
</div>
4. 只读属性 #
$refs 是只读的,不应该修改:
html
<div x-data>
<input x-ref="input">
<button @click="$refs.input = null">
错误:不应该修改 $refs
</button>
</div>
最佳实践 #
1. 优先使用声明式方式 #
不推荐:
html
<div x-data>
<input x-ref="input">
<button @click="$refs.input.value = 'Hello'">设置值</button>
</div>
推荐:
html
<div x-data="{ value: '' }">
<input x-model="value">
<button @click="value = 'Hello'">设置值</button>
</div>
2. 用于必须直接操作 DOM 的场景 #
html
<div x-data>
<input x-ref="input">
<button @click="$refs.input.focus()">聚焦</button>
<button @click="$refs.input.select()">全选</button>
</div>
3. 配合 $nextTick #
html
<div x-data="{
show: false,
focus() {
this.show = true
this.$nextTick(() => this.$refs.input.focus())
}
}">
<button @click="focus()">显示并聚焦</button>
<input x-ref="input" x-show="show">
</div>
小结 #
x-ref 指令要点:
- 给 DOM 元素添加引用名称
- 通过
$refs访问元素 - 用于需要直接操作 DOM 的场景
- 注意访问时机和
x-if的影响 - 优先使用声明式方式
至此,我们已经学习了 Alpine.js 的主要内置指令。下一章,我们将学习响应式系统。
最后更新:2026-03-28