简介
- vue(读作 /vju:/,类似view)是一套用于构建用户界面的渐进式框架。
- vue不支持IE8及以下版本。
- 安装:
- 直接下载并用
<script>引入,vue会被注册为一个全局变量。注意:在开发环镜下不要使用压缩版本,否则会失去所有常见错误相关的警告。 npm安装:在使用vue构建大型应用时推荐使用npm安装。安装方式:npm install vue --save- 查看vue的版本控制台:vue -V;
- 直接下载并用
- vue的优点:
- 体积小
- 更高的运行效率
- 双向数据绑定,让开发者不用再担心操作dom对象,把更多的精力投入到业务逻辑上。
- 生态丰富、学习成本低。
- MVVM:
- model: 模型,数据对象(data)
- view:视图,模板页面
- viewModel:视图模型(vue的实例)
模板语法
模板的理解
- 动态的 html 页面
- 包含了一些 js 语法的代码
- 双括号表达式
- 指令(以 v-开头的自定义标签属性)
双括号表达式
- 语法:
{{exp}} - 功能:向页面输出数据
- 可以调用对象的方法
指令一:强制数据绑定
- 功能:指定变化的属性值
- 完整写法:
v-bind:xxx= 'yyy' //yyy会作为表达式解析执行。 - 简洁写法:
:xxx= 'yyy'
指令二:绑定事件监听
- 功能:绑定事件名的回调函数
- 完整写法:
v-on:事件名= 'xxx'v-on:事件名= 'xxx(参数)'v-on:事件名.事件修饰符= 'xxx'
- 简洁写法:
@事件名= 'xxx'@事件名= 'xxx(参数)'@事件名.事件修饰符= 'xxx'
参考代码:
<div id="app">
<h2>1. 双大括号表达式</h2>
<p>{{msg}}</p>
<p>{{msg.toUpperCase()}}</p>
<h2>2. 指令一:强制数据绑定</h2>
<p><a href="url">访问指定站点1</a></p> <!-- 不可用 -->
<p><a v-bind:href="url">访问指定站点2</a></p>
<p><a :href="url">访问指定站点3</a></p>
<h2>指令二:绑定事件监听</h2>
<button type="button" v-on:click="handleClick">点我1</button>
<button type="button" @click="handleClick">点我2</button>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'hello',
url: 'http://www.baidu.com',
},
methods: {
handleClick() {
alert('hello word');
},
},
});
</script>
声明式渲染
- Vue.js的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统。
插值表达式渲染
- 可以通过
{{ Mustache }}插值表达式快速的渲染出元素中的内容 - 参考下面的代码
<div id="app"> {{ message }} </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> const app = new Vue({ el: '#app', // el: element 的简写。'#app' ,表示选中id为app 的元素。 data: { // data: 存放变量和数据 message: 'hello word', }, }); </script>
v-bind 绑定元素特性
v-bind特性被称为指令。指令带有前缀v-, 以表示它们是Vue 提供的特殊属性。 在上面的列子中,该指令的意识是: "将这个元素节点的title特性和 Vue实例的message属性保存一致"- 参考下面的代码:
<div id="app"> <p v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</p> </div> <script src="js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '页面加载于: ' + new Date().toLocaleString(), }, }); </script>
v-text 渲染页面
v-text: 更新元素的textContent。如果要更新部分的textContent,需要使用{{ Mustache }}插值表达式。- 参考下面的代码:
<p v-text="msg"></p> <!-- 和下面的一样 --> <p >{{ msg }}</p>
v-html 渲染页面
v-html: 更新元素的innerHTML。注意:内容按普通 HTML插入,不会做为 Vue 模板进行编译。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来代替。- 在动态网站上渲染HTML是非常危险的,因为容易导致
xss攻击。只在可信内容上使用v-html,永不用在用户提交的内容上。 - 在单文件组件里,
scoped的样式不会用在v-html内部,因为那部分HTML没有被vue的模板编译器预处理。如果你希望针对v-html的内容设置带作用域的css,可以替换为css Modules或用一个额外的全局<style>元素手动设置类似 BEM 的作用域策略。 - 参考下面代码:
<p v-html="html"></p>
计算属性和监视
计算属性
- 在
computed属性对象中定义计算属性的方法 - 在页面中使用
{{方法名}}来显示计算的结果 - 计算属性的方法什么时候调用:
- 初始化显示时
- 当相关的data属性数据发生改变的时候。
监视属性
- 通过vm对象的 $watch() 或 watch 配置来监视指定的属性。如果指定
deep:true则会启用深度监视 - 当属性变化时,回调函数自动调用,在函数内部进行计算。
- 不应该使用箭头函数定义 watch 函数
计算属性高级
- 通过 getter/setter实现对属性数据的显示和监视
- 计算属性存在缓存,多次读取只执行一个getter计算。
- getter: 属性的get方法。是一个回调函数,当需要读取当前属性的值时执行。计算相关属性的数据,并返回对应的值
- setter: 属性的set(在这里是监视的意思)方法。是一个回调函数,监视当前属性值的变化,当当前属性的值发生变化时执行,更新相关的数据
参考代码
<div id="dome">
<p>姓:<input type="text" v-model="firstName"></p>
<p>名:<input type="text" v-model="lastName"></p>
<p>姓名(单向1):<input type="text" v-model="fullName1"></p>
<p>姓名(单向2):<input type="text" v-model="fullName2"></p>
<p>姓名(双向3):<input type="text" v-model="fullName3"></p>
<ul>
<li>{{fullName1}}</li>
<li>{{fullName1}}</li>
<li>{{fullName1}}</li>
</ul>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#dome',
data: {
firstName: 'A',
lastName: 'B',
fullName2: 'A B',
},
computed: {
fullName1() {
console.log('fullName1');
return this.firstName + ' ' + this.lastName;
},
fullName3: {
//回调函数,当需要读取当前属性的值时执行。计算相关属性的数据,并返回对应的值
get() {
return this.firstName + ' ' + this.lastName;
},
//回调函数,监视当前属性值的变化,当当前属性的值发生变化时执行,更新相关的数据
set(value) {
[this.firstName, this.lastName] = value.split(' ');
}
},
},
watch: {
firstName(newVal, oldVal) {
this.fullName2 = newVal + ' ' + this.lastName;
},
},
});
vm.$watch('lastName', (newVal, oldVal) => {
console.log(this);
this.fullName2 = this.firstName2 + ' ' + newVal;
});
Class 与 Style 绑定
理解
- 在应用界面中,某个(些)元素的样式是变化的
- class/style绑定就是专门用来实现动态样式效果的技术。
class绑定
- 语法:
:class= 'xxx' - 表达式可以是字符串:
'classA' - 表达式可以是对象:
{classA:isA, classB:isB} - 表达式是数组:
[ 'classA', 'classB' ]
style 绑定
- 语法:
:style= "{color:activeColor,fontSize:fontSize+'px' }" - 其中
activeColor/fontSize是data中的属性
参考代码:
<style>
.aClass {
color: red;
}
.bClass {
color: blue;
}
.size {
font-size: 30px;
}
</style>
<div id="app">
<h2>class样式绑定</h2>
<p class="size" :class="aClass">class="XXX"</p>
<p :class="{aClass:isA,bClass:isB}">class="XXX"</p>
<p :class="['aClass','size']">class="XXX"</p>
<h2>style样式绑定</h2>
<p :style="{color:activeColor,fontSize:fontSize+'px'}">style动态样式绑定</p>
<button type="button" @click="updata">更新</button>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
aClass: 'aClass',
isA: true,
isB: false,
activeColor: 'pink',
fontSize:'30'
},
methods: {
updata() {
this.aClass = 'bClass';
this.isA=false;
this.isB = true;
}
},
});
</script>
条件与循环
v-show
v-show根据表达式之真假,切换元素的displaycss属性。当条件发生变化时该指令触发过渡效果。如果需要频繁切换v-show较好。- 参考下面的代码:
<div id="app"> <p v-show="show">展示</p> <p v-show="hidden">隐藏</p> </div> <script src="js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { show: true, hidden:false, }, }); </script>
v-if v-else-if v-else
1.v-if: 根据表达式的值的真假条件渲染元素。在切换时元素的数据绑定/组件被销毁并重建。如果元素是 <template> ,将提出它的内容作为条件块。
2. 当 v-if 和 v-for 一起使用时,v-for 的优先级比 v-if 更高。
3. v-else:为 v-if 或者 v-else-if 添加 "else 块"。前一兄弟元素必须要有 v-if 或者 v-else-if
4. v-else-if: 表示 v-if 的 "else if 块",可以链式调用。前一兄弟元素必须要有 v-if 或 v-else-if
5. 参考下面的代码:
```
a
b
c
d
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {},
});
</script>
```
v-for
-
v-for:基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法alias in expression,为当前遍历的元素提供别名。另外也可以为数组索引指定别名(或者是用于对象的键) -
v-for默认行为试着不改变整体,而是替换元素。- 为了给vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一的
key属性。 - 建议尽可能在使用
v-for时提供key属性。除非遍历时输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。 key属性是vue识别节点的一个通用机制,key并不仅仅只与v-for特别关联,它还具有其它用途。
- 为了给vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一的
-
使用 v-for 循环数组
<div id="app"> <p v-for="(item, index) in list">{{ index }}---{{ item }}</p> </div> <script src="js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { list: [1, 2, 3, 4, 5, 6], }, }); </script> -
使用 v-for 循环对象
<div id="app"> <p v-for="(val, key) in info" >{{key}}---{{val}}</p> </div> <script src="js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { info: {id:1,name:'小明',age:18, sex: '男'}, }, }); </script> -
使用 v-for 循环包含数组的对象
<div id="app"> <p v-for="(val, key) in list" :key="val.id"> 编号:{{val.id}} 姓名:{{val.name}} 年龄:{{val.age}} 性别:{{val.sex}} </p> </div> <script src="js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { list: [ {id:1,name:'小明',age:18, sex: '男'}, {id:2,name:'小红',age:12, sex: '女'}, {id:3,name:'小光',age:13, sex: '男'}, {id:4,name:'小花',age:15, sex: '女'}, {id:5,name:'小黄',age:11, sex: '男'}, ], }, }); </script>
列表搜索、排序和过滤
- 参考代码
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app" v-cloak>
<input type="text" v-model="searchName">
<ul>
<li v- v-for="(item,index) in filterPersons" :key="index">
{{index}}--{{item.name}}--{{item.age}}
</li>
</ul>
<button @click="orderPerson(1)">按年龄升序</button>
<button @click="orderPerson(2)">按年龄降序</button>
<button @click="orderPerson(0)">原本顺序</button>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
orderType: 0, // 0表示原有的顺序,1表示升序,2表示降序
persons: [
{name: 'jack', age: 18},
{name: 'tom', age: 16},
{name: 'toy', age: 19},
{name: 'alis', age: 17},
],
searchName: '',
},
computed: {
// 得到根据searchName过滤后的成员
filterPersons() {
console.log(this);
const {orderType, persons, searchName} = this;
// 根据searchName过滤数组persons
const fpersons = persons.filter((v) => {
return v.name.includes(searchName);
});
// 排序
if (orderType !== 0) {
fpersons.sort((p1, p2) => {
if (orderType === 1) { // 1表示升序 要返回负数
return p1.age - p2.age;
} else { // 降序 要返回正数
return p2.age - p1.age;
}
});
}
return fpersons;
},
},
methods: {
orderPerson(orderType) {
this.orderType = orderType;
}
},
});
事件处理
绑定监听:
- v-on:xxx= 'fun'
- @xxx= 'fun'
- @xxx= 'fun(参数)'
- 默认事件形参:event
- 隐含属性对象:$event
事件修饰符
.prevent:阻止事件的冒泡行为event.preventDefault().stop: 停止事件冒泡event.stopPropagation().selt: 仅当点击绑定事件的对应元素,才触发事件。
按键修饰符
.keycode:操作的是某个keycode值的键.keyName:操作的某个按键名的键(少部分)
参考代码:
<div id="example">
<h2>1. 绑定监听</h2>
<button type="button" @click="test1">test1</button>
<button type="button" @click="test2('hello')">test2</button>
<button type="button" @click="test3">test3</button>
<button type="button" @click="test4(123,$event)">test4</button>
<h2>2. 事件修饰符</h2>
<div style="width: 200px;height: 200px;background-color:pink;" @click.self="test5">
<div style="width: 100px;height: 100px;background-color:purple;" @click.stop="test6"></div>
<a href="http://www.baidu.com" @click.prevent="test7">去百度</a>
</div>
<h2>3. 按键修饰符</h2>
<input type="text" @keyup.13="test8">
<input type="text" @keyup.enter="test8">
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#example',
data: {
test1() {
alert('test1');
},
test2(msg) {
alert(msg);
},
test3(event) {
console.log(event);
alert(event.target.innerHTML);
},
test4(msg,event) {
alert(`${msg}----${event.target.innerText}`);
},
test5() {
alert('test5');
},
test6() {
alert('test6');
},
test7() {
alert('test7');
},
test8(event) {
alert(event.target.value);
}
},
});
</script>
表单数据的自动收集
- 对于 input、select[option]和 textarea 表单元素使用 v-model 指令实现双向数据绑定
参考代码:
<div id="app">
<form action="http://www" @submit.prevent="handleSubmit">
<div>
<label for="name">姓名:</label>
<input type="text" id="name" v-model="formData.name">
</div>
<div>
<label for="password">密码:</label>
<input type="password" id="password" v-model="formData.password">
</div>
<fieldset class="radios">
<legend>性别:</legend>
<div>
<input type="radio" id="male" value="男" v-model="formData.sex">
<label for="male">男</label>
</div>
<div>
<input type="radio" id="female" value="女" v-model="formData.sex">
<label for="female">女</label>
</div>
</fieldset>
<fieldset class="checkbox">
<legend>爱好:</legend>
<div>
<input type="checkbox" id="basketball" value="basketball" v-model="formData.like">
<label for="basketball">篮球</label>
</div>
<div>
<input type="checkbox" id="football" value="football" v-model="formData.like">
<label for="football">足球</label>
</div>
<div>
<input type="checkbox" id="pingPong" value="pingPong" v-model="formData.like">
<label for="pingPong">乒乓球</label>
</div>
</fieldset>
<div>
<label for="city">城市:</label>
<select id="city" v-model="formData.cityId">
<option>未选择</option>
<option :value="item.id" v-for="(item,index) in allCity" :key="index">{{item.name}}</option>
</select>
</div>
<div>
<label for="introduce">介绍:</label>
<textarea cols="30" rows="3" id="introduce" v-model="formData.introduce"></textarea>
</div>
<button type="submit">注册</button>
</form>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
allCity: [
{id:1, name: 'BJ'},
{id:2, name: 'SH'},
{id:3, name: 'GD'},
],
formData: {
name: '',
password:null,
sex: '女',
like: ['pingPong'],
cityId: null,
introduce:null,
}
},
methods: {
handleSubmit() {
console.log(JSON.stringify(this.formData));
}
},
});
</script>
生命周期
生命周期流程图

vue 生命周期分析
- 初始化显示
beforeCreate()created()beforeMount()mounted()
- 更新状态:this.xxx= value
beforeUpdate()updated()
- 销毁 vue 实例:vm.$destroy()
beforeDestroy()destroyed()
常用的生命周期方法
mounted(): 发送 ajax 请求,启动定时器等异步任务beforeDestroy(): 做收尾工作,如:清除定时器。
参考代码
<div id="app" v-cloak>
<button type="button" @click="detroyVM">destroy vm</button>
<p v-show="isShow">{{msg}}</p>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: true,
msg: '每隔一秒显示',
},
methods: {
detroyVM() {
vm.$destroy();
}
},
//------- 生命周期函数 --------
// 1. 初始化阶段
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('mounted');
this.intervalID = setInterval(() => {
console.log('--------');
this.isShow = !this.isShow;
}, 1000);
},
// 2. 更新阶段
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
// 3. 死亡阶段
beforeDestroy() {
console.log('beforeDetroy');
clearInterval(this.intervalID);
},
destroyed() {
console.log('destroyed');
}
});
</script>
动画
vue 动画的理解
- 操作
css的transition或animation - vue 会给目标元素添加/移除特定的 class
- 过渡的相关类名
xxx-enter-active: 指定显示的 transitionxxx-leave-active:指定隐藏的 transitionxxx-enter/xxx-leave-to: 指定隐藏时的样式
- vue 动画流程图:

基本过渡动画的编码
- 在目标元素外包裹
<transition name= "xxx"> - 定义class样式
- 指定过渡样式:
transition - 指定隐藏时的样式:
opacity/其它
- 指定过渡样式:
参考代码
使用 transition
<style>
/*定义显示/隐藏进行中的样式*/
.xxx-enter-active {
transition: all 3s;
}
.xxx-leave-active {
transition: all 1s;
}
/*指定不显示时大样式*/
.xxx-enter,
.xxx-leave-to {
transform: translateX(30px);
opacity: 0;
}
</style>
<div id="app">
<button @click="isShow=!isShow">toggle</button>
<transition name="xxx">
<p v-show="isShow">下一秒我又回来了</p>
</transition>
</div>
<script src="js/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: true,
},
});
</script>
使用animation
<style>
.xxx-enter-active {
animation: bounce 1s;
}
.xxx-leave-active {
animation: bounce 1s reverse;
}
@keyframes bounce {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
<div id="app2">
<button @click="isShow=!isShow">toggle</button><br>
<transition name="xxx">
<p v-show="isShow" style="display: inline-block">下一秒我又回来了</p>
</transition>
</div>
<script src="js/vue.js"></script>
<script>
const vm2 = new Vue({
el: '#app2',
data: {
isShow: true,
},
});
</script>
过滤器
理解过滤器
- 功能:对要显示的数据进行特定格式化后再显示。
- 注意:并没有改变原本的数据,而是产生新的对应的数据。定义全局过滤器要在创建 Vue 实例之前
定义和使用过滤器
- 定义过滤器
Vue.filter(filterName,(value[,arg1,arg2,...)]) => { // 进行一定的数据处理 return newValue; }); - 使用过滤器
<div>{{myData | filterName}}</div>
<div>{{myData | filterName(arg)}}</div>
参考代码
<div id="app" v-cloak>
<p>完整版:{{date | dateFormat}}</p>
<p>年月日:{{date | dateFormat('YYYY-MM-DD')}}</p>
<p>时分秒:{{date | dateFormat('HH:mm:ss')}}</p>
</div>
<script src="js/vue.js"></script>
<script src="js/moment.min.js"></script>
<script>
Vue.filter('dateFormat', (value, format = 'YYYY-MM-DD HH:mm:ss') => {
return moment().format(format);
});
const vm = new Vue({
el: '#app',
data: {
date: new Date(),
},
});
</script>
指令
内置指令
v-text:更新元素的 textContentv-html:更新元素的 innerHTMLv-if: 如果为true,当前标签才会输出到页面v-else-if:如果为true,当前标签才会输出到页面v-else:如果为false,当前标签才会输出到页面v-show:通过display样式来控制显示/隐藏v-bind:强制绑定解析表达式,可以简写为:v-on:绑定事件监听,一般简写为@v-for:遍历对象/数组v-model:双向数据绑定ref:指定唯一标识,vue对象通过$refs属性访问这个元素对象v-cloak:防止闪现,与css配合:[v-cloak]{display:none;}v-slot:插槽指令
自定义指令
- 注册全局指令
Vue.directive('upper-text', (el,binding) => { el.innerText = binding.value.toUpperCase(); }); - 注册局部指令
// 自定义局部指令 directives: { 'lower-text'(el,binding) { el.innerText = binding.value.toLowerCase(); }, }
参考代码
-
内置指令
<style> [v-cloak] { display: none; } </style> <div id="app" v-cloak> <button @click="eject">弹出</button> <p ref="news">{{msg}}</p> </div> <script src="js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { msg: 'hello word', }, methods:{ eject() { // alert(Vue.$refs); console.log(this.$refs.news.innerText); }, }, }); </script> -
自定义指令
<div id="app"> <p v-upper-text="msg"></p> <p v-lower-text="msg"></p> </div> <div id="app2"> <p v-upper-text="msg"></p> <p v-lower-text="msg"></p> </div> <script src="js/vue.js"></script> <script> // 自定义全局指令 // el:指令属性所在的标签对象 // binding: 包含指令相关信息数据的对象。 Vue.directive('upper-text', (el,binding) => { el.innerText = binding.value.toUpperCase(); }); const vm = new Vue({ el: '#app', data: { msg: 'DOCTYPE html', }, // 自定义局部指令 directives: { 'lower-text'(el,binding) { el.innerText = binding.value.toLowerCase(); }, } }); const vm2= new Vue({ el: '#app2', data: { msg: 'DOCTYPE html', }, }); </script>
vue 插件
说明
- vue插件是一个包含 install 方法的对象
- 通过 install 方法给 Vue 或 Vue 实例添加方法,定义全局指令等
参考代码:
- 插件js
//========== 自定义vue插件 ======== (function () { const MyPlugin = {}; MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或属性 Vue.myGlobalMethod = function () { console.log('全局方法myGlobalMethod()'); }; // 2. 添加全局资源 Vue.directive('my-directive', (el, binding) => { el.innerText = binding.value.toUpperCase(); }); // 3. 添加实例方法 Vue.prototype.$myMethod = function (methodOptions) { console.log('实例方法$myMethod()'); }; }; // 向外暴露 MyPlugin window.MyPlugin = MyPlugin; })(); - 页面使用插件
<div id="app"> <!-- 使用插件定义的指令--> <p v-my-directive="msg"></p> </div> <script src="js/vue.js"></script> <script src="js/vue-myPlugin.js"></script> <script> // 使用插件 MyPlugin Vue.use(MyPlugin); // 内部会执行 MyPlugin.install(Vue) const vm = new Vue({ el: '#app', data: { msg: 'I love you', }, }); // 调用插件全局方法 Vue.myGlobalMethod(); // 调用插件实例属性 vm.$myMethod(); </script>