Vue是一个利用JavaScript编写的构建用户界面的框架,
所解决的问题就是:如何构建用户界面。
注:下文中所说的用户界面,特指浏览器的用户界面。
用户界面
浏览器中的用户界面,简单概括起来包含两部分:
- 页面内容;
- 响应用户行为;
所有Vue的工作就是如何把这两部分构建起来:
- 如何生成页面内容?
- 用户操作时,如何处理用户的行为?
页面内容
在生成页面内容时,不管是在服务端还是在客户端,都有模板的概念,这样就能根据不同的数据展示出不同的页面内容。
数据和模板绑定
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
Vue 把 data 中的数据渲染到模板中的 {{ message }} 位置,当数据变化时视图自动更新。
响应用户行为
Vue 通过 v-on 指令监听 DOM 事件,在触发时执行对应的方法。
<div id="app">
<p>{{ count }}</p>
<button v-on:click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
<script>
new Vue({
el: '#app',
data: { count: 0 },
methods: {
increment: function () { this.count++; },
decrement: function () { this.count--; }
}
});
</script>
要点:v-on:click 缩写为 @click,方法定义在 methods 中,通过 this 访问 data。
常用指令
v-bind:绑定属性
<!-- 缩写为 : -->
<img :src="imageUrl">
<div :class="{ active: isActive }">内容</div>
v-if / v-show:条件渲染
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
<!-- v-show 只切换 display,频繁切换时性能更好 -->
<p v-show="isVisible">可见</p>
v-for:列表渲染
<ul>
<li v-for="(item, index) in list" :key="item.id">
{{ index }} - {{ item.name }}
</li>
</ul>
使用 v-for 时必须提供 :key,帮助 Vue 高效更新 DOM。
v-model:表单双向绑定
<input v-model="name" placeholder="输入名字">
<p>你好,{{ name }}</p>
v-model 本质是 v-bind:value + v-on:input 的语法糖。
组件基础
组件是可复用的 Vue 实例,用来封装独立的 UI 单元:
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
});
<todo-item v-for="item in list" :key="item.id" :todo="item"></todo-item>
组件要点:props 接收父组件数据(单向流动),组件 data 必须是函数。
生命周期
Vue 实例从创建到销毁会触发一系列钩子函数:
new Vue({
created: function () {
// 实例已创建,data 可用,常用于发起数据请求
},
mounted: function () {
// DOM 已渲染,可以操作 DOM 元素
},
beforeDestroy: function () {
// 实例销毁前,清理定时器、解绑事件
}
});
最常用:created 发请求,mounted 操作 DOM。
完整示例:TodoList
<!DOCTYPE html>
<html>
<head>
<title>Vue TodoList</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<h2>待办事项</h2>
<div>
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="回车添加">
<button @click="addTodo">添加</button>
</div>
<ul>
<li v-for="todo in todos" :key="todo.id">
<span
:style="{ textDecoration: todo.done ? 'line-through' : 'none' }"
@click="todo.done = !todo.done">
{{ todo.text }}
</span>
<button @click="removeTodo(todo.id)">删除</button>
</li>
</ul>
<p v-show="todos.length">
共 {{ todos.length }} 项,已完成 {{ doneCount }} 项
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
newTodo: '',
nextId: 4,
todos: [
{ id: 1, text: '学习 Vue 基础', done: true },
{ id: 2, text: '做一个 TodoList', done: false },
{ id: 3, text: '学习组件', done: false }
]
},
computed: {
doneCount: function () {
return this.todos.filter(function (t) { return t.done; }).length;
}
},
methods: {
addTodo: function () {
var text = this.newTodo.trim();
if (!text) return;
this.todos.push({ id: this.nextId++, text: text, done: false });
this.newTodo = '';
},
removeTodo: function (id) {
this.todos = this.todos.filter(function (t) { return t.id !== id; });
}
}
});
</script>
</body>
</html>
这个例子覆盖了:v-model 双向绑定、@keyup.enter 事件处理、v-for 列表渲染、:style 动态样式、v-show 条件显示、computed 计算属性、methods 方法。
小结
Vue 入门围绕两条线:
- 数据到视图:data -> 模板 -> DOM(声明式渲染)
- 用户到数据:DOM 事件 -> methods -> 修改 data -> 视图自动更新
理解了这个双向循环,Vue 的响应式本质就清楚了。