Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。
使用双大括号语法进行文本插值:
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
结果: Hello Vue!
使用 v-html 指令输出真正的 HTML:
<div id="app">
<p>{{ rawHtml }}</p>
<p v-html="rawHtml"></p>
</div>
<script>
new Vue({
el: '#app',
data: {
rawHtml: '<span style="color: red">这是红色的文字</span>'
}
});
</script>
结果:
<span style="color: red">这是红色的文字</span>
这是红色的文字
v-html 指令。
指令是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式(除了 v-for)。
v-bind 用于动态绑定一个或多个特性,或一个组件 prop 到表达式。
<!-- 绑定一个属性 -->
<img v-bind:src="imageSrc">
<!-- 动态特性名 (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc">
<!-- 动态特性名缩写 -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName">
<div id="app">
<!-- 绑定href -->
<a v-bind:href="url">链接</a>
<!-- 绑定class -->
<div v-bind:class="{ active: isActive }">动态类</div>
<!-- 绑定style -->
<div v-bind:style="{ color: textColor, fontSize: size + 'px' }">动态样式</div>
</div>
<script>
new Vue({
el: '#app',
data: {
url: 'https://vuejs.org',
isActive: true,
textColor: 'red',
size: 20
}
});
</script>
<!-- 完整语法 -->
<a v-bind:href="url">链接</a>
<!-- 缩写 -->
<a :href="url">链接</a>
<!-- 动态参数缩写 (2.6.0+) -->
<a :[attributeName]="url">链接</a>
v-bind 的缩写是 :。例如 v-bind:href 可以缩写为 :href。
计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三'
},
computed: {
// 计算属性的 getter
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
// 带setter的计算属性
fullNameWithSetter: {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function(newValue) {
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[1] || '';
}
}
}
});
| 特性 | 计算属性 | 方法 |
|---|---|---|
| 缓存 | 有缓存 | 无缓存 |
| 调用方式 | 作为属性访问{{ fullName }} |
作为方法调用{{ getFullName() }} |
| 适用场景 | 复杂计算、性能敏感 | 事件处理、简单计算 |
<div id="cart-example">
<h4>购物车</h4>
<ul>
<li v-for="item in cart" :key="item.id">
{{ item.name }} - ¥{{ item.price }} × {{ item.quantity }}
</li>
</ul>
<p>总价: ¥{{ totalPrice }}</p>
<p>含税总价 (税率{{ taxRate * 100 }}%): ¥{{ totalPriceWithTax }}</p>
</div>
<script>
new Vue({
el: '#cart-example',
data: {
cart: [
{ id: 1, name: '商品A', price: 100, quantity: 2 },
{ id: 2, name: '商品B', price: 200, quantity: 1 },
{ id: 3, name: '商品C', price: 50, quantity: 5 }
],
taxRate: 0.1
},
computed: {
totalPrice: function() {
// 计算购物车总价
return this.cart.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
},
totalPriceWithTax: function() {
// 基于其他计算属性进行计算
return this.totalPrice * (1 + this.taxRate);
}
}
});
</script>
运行结果:
总价: ¥650
含税总价 (税率10%): ¥715
侦听器用于观察和响应 Vue 实例上的数据变动。当需要在数据变化时执行异步或开销较大的操作时,使用侦听器。
new Vue({
el: '#app',
data: {
question: '',
answer: '请先输入问题!'
},
watch: {
// 监听question的变化
question: function(newQuestion, oldQuestion) {
this.answer = '正在思考...';
this.getAnswer();
}
},
methods: {
getAnswer: function() {
// 模拟异步API调用
setTimeout(() => {
this.answer = '答案是:42';
}, 1000);
}
}
});
new Vue({
el: '#app',
data: {
user: {
name: '张三',
age: 25,
profile: {
email: 'zhangsan@example.com'
}
}
},
watch: {
// 深度侦听对象内部值的变化
user: {
handler: function(newVal, oldVal) {
console.log('user changed:', newVal);
},
deep: true, // 深度侦听
immediate: true // 立即执行一次
},
// 侦听对象特定属性
'user.name': function(newVal, oldVal) {
console.log('name changed:', newVal);
}
}
});
| 场景 | 使用计算属性 | 使用侦听器 |
|---|---|---|
| 数据变化时执行操作 | 推荐 适用于同步操作 | 推荐 适用于异步操作 |
| 需要返回一个值 | 必须 计算属性返回计算值 | 不适用 侦听器不返回值 |
| 开销大的操作 | 不推荐 计算属性会缓存结果 | 推荐 可以控制执行时机 |
| 响应多个数据变化 | 推荐 可以依赖多个数据 | 复杂 需要侦听多个数据 |
Vue 提供了 v-if, v-else-if, v-else 和 v-show 指令用于条件渲染。
<div id="app">
<!-- 基本用法 -->
<p v-if="show">显示内容</p>
<!-- v-if / v-else -->
<p v-if="score >= 60">及格</p>
<p v-else>不及格</p>
<!-- v-if / v-else-if / v-else -->
<div v-if="type === 'A'">类型A</div>
<div v-else-if="type === 'B'">类型B</div>
<div v-else-if="type === 'C'">类型C</div>
<div v-else>其他类型</div>
</div>
<script>
new Vue({
el: '#app',
data: {
show: true,
score: 85,
type: 'B'
}
});
</script>
<div id="app">
<!-- v-show 只是切换CSS的display属性 -->
<p v-show="isVisible">显示内容</p>
<!-- v-if 与 v-show 对比 -->
<div v-if="count > 0">v-if: 条件为真</div>
<div v-show="count > 0">v-show: 条件为真</div>
</div>
<script>
new Vue({
el: '#app',
data: {
isVisible: true,
count: 5
}
});
</script>
| 特性 | v-if | v-show |
|---|---|---|
| 初始渲染开销 | 条件为假时,元素不会被渲染到DOM | 元素始终会被渲染,只是通过CSS切换显示 |
| 切换开销 | 切换时元素会被销毁/重建,开销较高 | 切换时只是修改CSS属性,开销较低 |
| 适用场景 | 运行时条件很少改变,或需要避免初始渲染 | 需要频繁切换显示状态 |
| 与v-else配合 | 支持 | 不支持 |
v-if 时,元素可能无法被获取到,因为条件为假时元素不会存在于DOM中。而 v-show 的元素始终存在于DOM中,只是通过CSS控制显示。
使用 v-for 指令基于数组或对象渲染列表。
<div id="app">
<!-- 基本用法 -->
<ul>
<li v-for="item in items">
{{ item.name }}
</li>
</ul>
<!-- 带索引 -->
<ul>
<li v-for="(item, index) in items">
{{ index }}. {{ item.name }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: [
{ name: '苹果' },
{ name: '香蕉' },
{ name: '橙子' }
]
}
});
</script>
<div id="app">
<!-- 遍历对象 -->
<ul>
<li v-for="value in user">
{{ value }}
</li>
</ul>
<!-- 带键名和索引 -->
<ul>
<li v-for="(value, key, index) in user">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
user: {
name: '张三',
age: 25,
city: '北京'
}
}
});
</script>
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key 特性:
<div id="app">
<!-- 正确的做法:使用key -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
<input type="text" placeholder="输入内容">
</li>
</ul>
<!-- 错误的做法:不使用key -->
<ul>
<li v-for="item in items">
{{ item.name }}
<input type="text" placeholder="输入内容">
</li>
</ul>
<button @click="addItem">添加新项</button>
</div>
<script>
new Vue({
el: '#app',
data: {
items: [
{ id: 1, name: '第一项' },
{ id: 2, name: '第二项' },
{ id: 3, name: '第三项' }
]
},
methods: {
addItem: function() {
this.items.unshift({
id: Date.now(),
name: '新项' + (this.items.length + 1)
});
}
}
});
</script>
说明: 使用 :key 可以确保在列表重新排序时,Vue能够正确识别每个元素,避免不必要的DOM操作。
:key 为 v-for 的元素提供唯一标识,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获得性能提升。
使用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
<div id="app">
<!-- 直接执行代码 -->
<button v-on:click="counter += 1">
点击增加: {{ counter }}
</button>
<!-- 调用方法 -->
<button v-on:click="greet">打招呼</button>
<!-- 内联语句中调用方法 -->
<button v-on:click="say('Hello')">说 Hello</button>
<!-- 访问原始DOM事件 -->
<button v-on:click="warn('表单不能提交', $event)">
提交
</button>
</div>
<script>
new Vue({
el: '#app',
data: {
counter: 0,
name: 'Vue.js'
},
methods: {
greet: function(event) {
alert('Hello ' + this.name + '!');
if (event) {
alert(event.target.tagName);
}
},
say: function(message) {
alert(message);
},
warn: function(message, event) {
if (event) {
event.preventDefault();
}
alert(message);
}
}
});
</script>
<div id="app">
<!-- 阻止默认行为 -->
<a v-on:click.prevent="doSomething" href="#">链接</a>
<!-- 停止事件冒泡 -->
<div v-on:click.stop="doSomething">
点击这里不会冒泡
</div>
<!-- 事件只会触发一次 -->
<button v-on:click.once="doSomething">只触发一次</button>
<!-- 按键修饰符 -->
<input v-on:keyup.enter="submit" placeholder="按回车提交">
<!-- 系统修饰键 -->
<button v-on:click.ctrl="doSomething">Ctrl+点击</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
doSomething: function() {
console.log('事件处理');
},
submit: function() {
console.log('表单提交');
}
}
});
</script>
@click.stop.prevent。
| 修饰符 | 作用 | 示例 |
|---|---|---|
.stop |
阻止事件冒泡 | @click.stop="handleClick" |
.prevent |
阻止默认行为 | @submit.prevent="handleSubmit" |
.capture |
使用事件捕获模式 | @click.capture="handleClick" |
.self |
只当事件是从元素本身触发时触发回调 | @click.self="handleClick" |
.once |
事件只触发一次 | @click.once="handleClick" |
.passive |
提升移动端滚动性能 | @scroll.passive="handleScroll" |
使用 v-model 指令在表单输入元素上创建双向数据绑定。
<div id="app">
<!-- 文本输入框 -->
<input v-model="message" placeholder="输入内容">
<p>输入的内容: {{ message }}</p>
<!-- 多行文本 -->
<textarea v-model="multilineText" placeholder="多行文本"></textarea>
<p style="white-space: pre-line">{{ multilineText }}</p>
<!-- 复选框 -->
<div>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked ? '已选中' : '未选中' }}</label>
</div>
<!-- 多个复选框 -->
<div>
<input type="checkbox" id="vue" value="Vue" v-model="checkedNames">
<label for="vue">Vue</label>
<input type="checkbox" id="react" value="React" v-model="checkedNames">
<label for="react">React</label>
<input type="checkbox" id="angular" value="Angular" v-model="checkedNames">
<label for="angular">Angular</label>
<p>选择的框架: {{ checkedNames }}</p>
</div>
<!-- 单选按钮 -->
<div>
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<p>选择的值: {{ picked }}</p>
</div>
<!-- 选择框 -->
<div>
<select v-model="selected">
<option disabled value="">请选择</option>
<option value="A">选项A</option>
<option value="B">选项B</option>
<option value="C">选项C</option>
</select>
<p>选择的选项: {{ selected }}</p>
</div>
<!-- 多选选择框 -->
<div>
<select v-model="multiSelected" multiple style="width: 200px">
<option value="A">选项A</option>
<option value="B">选项B</option>
<option value="C">选项C</option>
</select>
<p>选择的选项: {{ multiSelected }}</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '',
multilineText: '',
checked: false,
checkedNames: [],
picked: '',
selected: '',
multiSelected: []
}
});
</script>
v-model 有一些修饰符,可以改变默认行为:
.lazy 修饰符
在 change 事件之后进行同步,而不是在 input 事件之后:
<!-- 在"change"时而非"input"时更新 -->
<input v-model.lazy="msg">
.number 修饰符
将用户的输入值转为数值类型:
<!-- 自动将输入值转为数值 -->
<input v-model.number="age" type="number">
.trim 修饰符
自动过滤用户输入的首尾空白字符:
<!-- 自动过滤输入的首尾空白字符 -->
<input v-model.trim="msg">
本教程详细介绍了Vue.js的基本语法,包括:
v-if、v-for等指令的使用v-on指令和事件修饰符v-model双向数据绑定这些是Vue.js的核心语法,掌握它们是使用Vue.js进行开发的基础。在实际开发中,这些语法会经常组合使用。