一. Vue概述
尤雨溪:Vue.js的创建者
- 2016年5月,Vue2发布
- 2020年9月,Vue3发布
Vue: (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架
渐进式框架就是,我们可以在项目中一点点来引入Vue,而不一定需要全部使用Vue来开发整个项目。
官网:https://cn.vuejs.org/v2/guide/
- 易用:熟悉HTML、CSS、JavaScript知识后,可快速上手Vue
- 灵活:Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合
- 高效:20kB运行大小,超快虚拟 DOM
注意:下面我们介绍的是Vue2.x版本的。
二. 开发模式对比
原生JS:
<div id="msg"></div>
<script type="text/javascript">
var msg = 'Hello World';
var div = document.getElementById('msg');
div.innerHTML = msg;
</script>
jQuery:
<div id="msg"></div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
var msg = 'Hello World';
$('#msg').html(msg);
</script>
Vue.js之HelloWorld实现:
使用Vue将 helloworld 渲染到页面上:
- 实例参数分析
el:元素的挂载位置(值可以是CSS选择器或者DOM元素)
data:模型数据(值是一个对象) - 插值表达式用法
将数据填充到HTML标签中
插值表达式支持基本的计算操作 - Vue代码运行原理分析
概述编译过程的概念(Vue语法 → 原生语法)
三. Vue模板语法
1 - 前端渲染
前端渲染就是把数据填充到HTML标签中。
前端渲染有如下三种方式:
- 原生js拼接字符串
- 使用前端模板引擎
- 使用vue特有的模板语法
1. 原生js拼接字符串
基本上就是将数据以字符串的方式拼接到HTML标 签中,前端代码风格大体上如下所示。
var d = data.weather;
var info = document.getElementById('info');
info.innerHTML = '';
for(var i=0;i<d.length;i++){
var date = d[i].date;
var day = d[i].info.day;
var night = d[i].info.night;
var tag = '';
tag += '<span>日期:'+date+'</sapn><ul>';
tag += '<li>白天天气:'+day[1]+'</li>'
tag += '<li>白天温度:'+day[2]+'</li>'
tag += '<li>白天风向:'+day[3]+'</li>'
tag += '<li>白天风速:'+day[4]+'</li>'
tag += '</ul>';
var div = document.createElement('div');
div.innerHTML = tag;
info.appendChild(div);
}
缺点:不同开发人员的代码风格差别很大,随着业务的复杂,后期的维护变得逐渐困难起来。
2. 使用前端模板引擎
如下代码是基于模板引擎art-template
的一段代码,与拼接字符串相比,代码明显规范了很多,它拥有自己的一套模板语法规则。
<script id="abc" type="text/html">
{{if isAdmin}}
<h1>{{title}}</h1>
<ul>
{{each list as value i}}
<li>索引 {{i + 1}} :{{value}}</li>
{{/each}}
</ul>
{{/if}}
</script>
优点:大家都遵循同样的规则写代码,代码可读性明显提高了,方便后期的维护。
缺点:没有专门提供事件机制。
3. 使用Vue模板语法
第三种方式就是使用Vue模板语法了,下面我们详细讲述一下Vue模板语法。
2 - 指令
- 指令的本质就是自定义属性
- 指令的格式:以v-开始(比如:v-cloak)
1. v-cloak指令
- 插值表达式存在的问题:“闪动”
原因:Vue会先把 {{}} 显示在页面中,然后再迅速替换成具体的值,所以会有闪动问题 - 如何解决该问题:使用v-cloak指令
- 解决该问题的原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终的结果
<style type="text/css">
/*
1、通过属性选择器选择带有属性v-cloak的标签,让他隐藏
*/
[v-cloak]{
/* 元素隐藏 */
display: none;
}
</style>
<body>
<div id="app">
<!-- 2、 让带有插值语法的标签添加 v-cloak 属性,在数据渲染完之后,v-cloak属性会被自动去除,v-cloak一旦移除也就是没有这个属性了,属性选择器就选择不到该标签,也就是对应的标签会变为可见
-->
<!-- 背后的原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终的结果 -->
<div v-cloak >{{msg}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el:指定元素id是app的元素
el: '#app',
// data:里面存储的是数据,是个对象
data: {
msg: 'Hello Vue'
}
});
</script>
</body>
</html>
虽然v-cloak指令可以解决闪动的问题,但是我们很少用,因为闪动就闪动吧,很少管,不管也没事。
2. v-text 填充纯文本
- v-text指令用于将数据填充到标签中,作用和插值表达式类似,但是没有闪动问题
- 如果数据中有HTML标签会将html标签一并输出
- 注意:此处为单向绑定,数据对象上的值改变,插值会发生变化;但是当插值发生变化并不会影响数据对象的值
<div id="app">
<!--
注意:在指令中不要写插值语法,直接写对应的变量名
-->
<p v-text="msg"> </p>
<p>
<!-- Vue中只有在标签的内容中,才用插值语法 -->
{{msg}}
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'Hello Vue.js'
}
});
</script>
很少用,我们一般还是用插值表达式。
3. v-html 填充HTML片段
- 用法和v-text 相似,但是他可以将HTML片段填充到标签中
- 有安全问题:一般只在可信任内容上使用
v-html
,永不用在用户提交的内容上 - 它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。
<div id="app">
<p v-html="html"></p> <!-- 输出:html标签在渲染的时候被解析 -->
<p>{{message}}</p> <!-- 输出:<span>通过双括号绑定</span> -->
<p v-text="text"></p> <!-- 输出:<span>html标签在渲染的时候被源码输出</span> -->
</div>
<script>
let app = new Vue({
el: "#app",
data: {
message: "<span>通过双括号绑定</span>",
html: "<span>html标签在渲染的时候被解析</span>",
text: "<span>html标签在渲染的时候被源码输出</span>",
}
});
</script>
4. v-pre 填充原始信息
- 显示原始信息,跳过编译过程
- 跳过这个元素和它的子元素的编译过程。
- 一些静态的内容不需要编译加这个指令可以加快渲染
<span v-pre>{{ this will not be compiled }}</span>
<!-- 显示的是:{{ this will not be compiled }} -->
<span v-pre>{{msg}}</span>
<!-- 即使data里面定义了msg这里仍然是显示的:{{msg}} -->
<script>
new Vue({
el: '#app',
data: {
msg: 'Hello Vue.js'
}
});
</script>
加快渲染的指令,也很少用。
5. v-once 只编译一次
执行一次性的插值(当数据改变时,插值处的内容不会继续更新)
<!-- 即使data里面定义了msg,后期我们修改了msg,仍然显示的是第一次data里面存储的数据即 Hello Vue.js -->
<span v-once>{{msg}}</span>
<script>
new Vue({
el: '#app',
data: {
msg: 'Hello Vue.js'
}
});
</script>
上面我们讲的数据插值,以及上面几个指令都是数据绑定,都是响应式的(数据的变化导致页面内容的变化)。
3 - 双向数据绑定指令
1. 什么是双向数据绑定?
- 当数据发生变化的时候,视图也就发生变化
- 当视图发生变化的时候,数据也会跟着同步变化
2. v-model 双向数据绑定
v-model是一个指令,限制在 <input>、<textarea>、<select>、components
中使用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
<div>
<!-- 当输入框中内容改变的时候,下面的msg会自动更新 -->
<input type="text" v-model='msg'>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
双向数据绑定
1、从页面到数据
2、从数据到页面
*/
var vm = new Vue({
el: '#app',
data: {
// 当这里的msg改变的时候,上面输入框的值也会自动更新
msg: 'Hello Vue'
}
});
</script>
</body>
</html>
3. MVVM设计思想
MVC 是后端的分层开发概念,MVVM是前端视图层的概念,主要关注于视图层分离,也就是说:MVVM把前端的视图层,分为了三部分 Model、View、 ViewModel。
① M(model) 数据层 Vue中数据层都放在 data 里面
② V(view) 视图 Vue中 view 即我们的 HTML 页面
③ VM(View-Model) 控制器 将数据和视图层建立联系,vm 即 Vue 的实例
4 - 事件绑定
1. v-on: 事件绑定
用来绑定事件的,形式如:v-on:click 缩写为 @click。
2. 事件函数的绑定方式
- 直接绑定函数名称
<button v-on:click='say'>Hello</button>
- 绑定调用函数(虽然写的是say(),并不会调用函数,只有点击的时候才会调用函数),很少用
<button v-on:click='say()'>Say hi</button>
3. 事件函数中传入参数
- 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的参数
- 如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event
<body>
<div id="app">
<div>{{num}}</div>
<div>
<!-- 1、如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的参数 -->
<button v-on:click='handle1'>点击1</button>
<!-- 2、如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event -->
<button v-on:click='handle2(123, 456, $event)'>点击2</button>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
num: 0
},
methods: {
// 默认有事件对象
handle1: function(event) {
console.log(event.target.innerHTML)
},
// 事件对象作为最后一个参数
handle2: function(p, p1, event) {
console.log(p, p1)
console.log(event.target.innerHTML)
this.num++;
}
}
});
</script>
一般我们直接绑定函数名称,不传参数,因为基本上所有的数据都在data()中,我们可以直接拿,不用传递。
4. 事件修饰符
- 在事件处理程序中调用
event.preventDefault()
或event.stopPropagation()
是非常常见的需求 - Vue 不推荐我们操作DOM,为了解决这个问题,Vue.js 为
v-on
提供了事件修饰符,主要包括:.stop
、.prevent
、.self
- 修饰符是由点开头的指令后缀来表示的
<div>{{num}}</div>
<div v-on:click='handle0'>
<!-- 阻止冒泡,如果不阻止,点击按钮的时候通过冒泡的形式handle0也会触发,num值也会增加 -->
<button v-on:click.stop='handle1'>点击1</button>
</div>
<!-- 阻止默认行为 -->
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!--
handle2: function(event){
// 原来的阻止默认行为
// event.preventDefault();
}
-->
<!-- 修饰符可以串联,即阻止冒泡也阻止默认事件 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只当在 event.target 是当前元素自身时才会触发处理函数(就是点击的是自己) -->
<!-- 即事件不是从内部元素触发的(就是不是冒泡出来的) -->
<div v-on:click.self="doThat">...</div>
5. 按键修饰符
在做项目中有时会用到键盘事件,在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符,如:keyup.enter
、keydown.space
,其中keyup是弹起时触发,keydown是按下时触发。
<!-- 当enter弹起时,调用 vm.submit() -->
<input v-on:keyup.enter="submit">
<!-- 当delete或者space弹起时,调用 vm.alertMe() -->
<input v-on:keyup.delete.space="alertMe" >
<!-- 当keyCode是13的按键弹起时,调用 vm.submit() -->
<input v-on:keyup.13="submit">
<!--
常用的按键修饰符
.enter => enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) => 删除键
.esc => 取消键
.space => 空格键
.up => 上
.down => 下
.left => 左
.right => 右
-->
<script>
var vm = new Vue({
el:"#app",
methods: {
submit:function(){},
alertMe:function(){},
}
})
</script>
6. 自定义按键修饰符别名
在Vue中可以通过 Vue.config.keyCodes
自定义按键修饰符别名。
<div id="app">
<!-- 由于预先定义了keycode 116(即F5)的别名为f5,因此在文字输入框中按下F5,会触发prompt方法 -->
<input type="text" v-on:keydown.f5="prompt()">
</div>
<script>
// 自定义按键修饰符别名
// 名字是自定义的,但是对应的值必须是按键对应event.keyCode值
Vue.config.keyCodes.f5 = 116;
let app = new Vue({
el: '#app',
methods: {
prompt: function() {
alert('我是 F5!');
}
}
});
</script>
7. 案例:简单计算器
需求:实现简单的加法计算,分别输入数值a和数值b,点击计算按钮,结果显示在下面。
- 通过v-model指令实现数值a和数值b的绑定
- 给计算按钮绑定事件,实现计算逻辑
- 将计算结果绑定到对应位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>简单计算器</h1>
<div>
<span>数值A:</span>
<span>
<input type="text" v-model='a'>
</span>
</div>
<div>
<span>数值B:</span>
<span>
<input type="text" v-model='b'>
</span>
</div>
<div>
<button v-on:click='handle'>计算</button>
</div>
<div>
<span>计算结果:</span>
<!-- 使用v-text,数据响应式 -->
<span v-text='result'></span>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
简单计算器案例
*/
var vm = new Vue({
el: '#app',
data: {
a: '',
b: '',
result: ''
},
methods: {
handle: function(){
// 实现计算逻辑
this.result = parseInt(this.a) + parseInt(this.b);
}
}
});
</script>
</body>
</html>
5 - 属性绑定
1. v-bind: 响应地更新html属性
-
v-bind:
指令被用来响应地更新 HTML 属性 -
v-bind:
可以缩写为:
,所以v-bind:href
可以缩写为:href
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 绑定一个属性 -->
<a v-bind:href="url">百度</a>
<!-- 缩写 -->
<a :href="url">百度1</a>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/* 属性绑定 */
var vm = new Vue({
el: '#app',
data: {
url: 'http://www.baidu.com'
},
methods: {
handle: function(){
// 修改URL地址
this.url = 'http://itcast.cn';
}
}
});
</script>
</body>
</html>
2. v-model的底层实现原理分析
v-model的底层就是通过绑定value属性,然后通过监听input事件来处理值的变化。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
// v-model的底层实现原理
<input type="text" v-bind:value="msg" v-on:input='handle'>
// v-model的底层实现原理:简写如下
<input type="text" v-bind:value="msg" v-on:input='msg=$event.target.value'>
// v-model双向数据绑定
<input type="text" v-model='msg'>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/* v-model指令的本质 */
var vm = new Vue({
el: '#app',
data: {
msg: 'hello'
},
methods: {
handle: function(event){
// 使用输入域中的最新的数据覆盖原来的数据
this.msg = event.target.value;
}
}
});
</script>
</body>
</html>
6 - 样式绑定
1. class样式绑定
① 绑定对象语法
- 我们可以给 v-bind:class 一个对象,以动态地切换class。
- 注意:v-bind:class 指令可以与普通的class特性共存
- 绑定对象的时候,对象的属性名就是要渲染的类名,对象的属性值对应的是 data 中的数据,即是否要渲染这个类,是个布尔值。
- 我们也可以绑定一个返回对象的计算属性,这是很常用。
<div v-bind:class="{ active: isActive }"></div>
/*
1. v-bind 中支持绑定一个对象
如果绑定的是一个对象,则键为对应的类名 值为对应data中的数据
HTML最终渲染为 <ul class="box textColor textSize"></ul>
注意:
textColor,textSize 对应的渲染到页面上的CSS类名
isColor,isSize 对应vue data中的数据 如果为true 则对应的类名渲染到页面上
当 isColor 和 isSize 变化时,class列表将相应的更新,
例如,将isSize改成false,
class列表将变为 <ul class="box textColor"></ul>
*/
// v-bind:class
<ul class="box" v-bind:class="{textColor:isColor, textSize:isSize}">
<li>学习Vue</li>
<li>学习Node</li>
<li>学习React</li>
</ul>
<button v-on:click='handle'>切换</button>
<script>
var vm = new Vue({
el:'.box',
data:{
isColor:true,
isSize:true,
},
methods: {
handle: function(){
// 控制isColor的值在true和false之间进行切换
this.isColor = !this.isColor;
this.isSize = !this.isSize;
}
}
})
</script>
② 绑定数组语法
绑定数组的时候,数组里面存的是需要渲染的类名,就是 data 中的数据。
<div v-bind:class="[colorClass, sizeClass]"></div>
/*
2. v-bind 中支持绑定一个数组
数组中colorClass 和 sizeClass 对应为data中的数据
这里的colorClass 对用data 中的 textColor
这里的sizeClass 对用data 中的 textSize
*/
<ul class="box" :class="[colorClass, sizeClass]">
<li>学习Vue</li>
<li>学习Node</li>
<li>学习React</li>
</ul>
<button v-on:click='handle'>切换</button>
<script>
var vm= new Vue({
el:'.box',
data:{
colorClass:'textColor',
sizeClass:'textSize'
},
methods: {
handle: function(){
this.colorClass = '';
this.sizeClass = '';
}
}
})
</script>
③ class样式绑定语法细节
- 对象绑定和数组绑定可以结合使用
- class绑定的值可以简化传入对象名或数组名
- 默认的class会保留,不会被覆盖
-
v-bind:
可以缩写为:
,所以v-bind:class
可以简写为:class
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.active {
border: 1px solid red;
width: 100px;
height: 100px;
}
.error {
background-color: orange;
}
.test {
color: blue;
}
.base {
font-size: 28px;
}
</style>
</head>
<body>
<div id="app">
// 1、对象绑定和数组绑定可以结合使用
<div v-bind:class='[activeClass, errorClass, {test: isTest}]'>测试样式</div>
// 2、class绑定的值可以简化操作
// 对象简化,传入对象名
<div v-bind:class='objClasses'></div>
// 数组简化,传入数组名
<div v-bind:class='arrClasses'></div>
// 3、默认的class会保留,不会被覆盖
<div class="base" v-bind:class='objClasses'></div>
// 4、v-bind:class 可以简写为 :class
<div :class='objClasses'></div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
activeClass: 'active',
errorClass: 'error',
isTest: true,
arrClasses: ['active','error'],
objClasses: {
active: true,
error: true
}
},
methods: {
handle: function(){
// this.isTest = false;
this.objClasses.error = false;
}
}
});
</script>
</body>
</html>
2. style样式绑定
- 对象语法
<div v-bind:style="{color: activeColor, fontSize: fontSize}"></div>
- 数组语法
<div v-bind:style="[styleObj1, styleObj2]"></div>
// 绑定样式对象: 传入对象
// CSS属性名可以用驼峰式或短横线分隔
<div v-bind:style="{color: activeColor, fontSize: fontSize, background:'red' }">内联样式</div>
// 绑定样式对象: 传入对象名
<div v-bind:style="styleObject">绑定样式对象</div>'
// 绑定样式: 传入对象数组
// 组语法可以将多个样式对象应用到同一个元素
// 如果样式对象中有相同的属性,后面的会覆盖前面的
<div v-bind:style="[styleObj1, styleObj2]"></div>
// v-bind: 可以缩写为 :
<div :style="[styleObj1, styleObj2]"></div>
<script>
new Vue({
el: '#app',
data: {
activeColor: 'green',
fontSize: "30px"
styleObject: {
color: 'green',
fontSize: '30px',
background:'red'
},
styleObj1: {
color: 'red'
},
styleObj2: {
fontSize: '30px'
}
}
});
</script>
7 - 分支循环结构
1. v-if
通过条件判断是否渲染某个元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-if='score>=90'>优秀</div>
<div v-else-if='score<90&&score>=80'>良好</div>
<div v-else-if='score<80&&score>60'>一般</div>
<div v-else>比较差</div>
<div v-show='flag'>测试v-show</div>
<button v-on:click='handle'>点击</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
v-show的原理:控制元素样式是否显示 display:none
*/
var vm = new Vue({
el: '#app',
data: {
score: 10,
flag: false
},
methods: {
handle: function(){
this.flag = !this.flag;
}
}
});
</script>
</body>
</html>
2. v-if与v-show的区别
- v-if是动态的向DOM树内添加或者删除DOM元素,v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件。
- v-show本质就是标签display设置为none,控制隐藏。v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
3. 循环结构
① v-for遍历数组
用于循环的数组里面的值可以是对象,也可以是普通元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>水果列表</div>
<ul>
<!-- 遍历数组(数组里面是字符串) -->
<li v-for='item in fruits'>{{item}}</li>
<!-- 遍历数组(数组里面是字符串),有index -->
<li v-for='(item, index) in fruits'>{{item + '---' + index}}</li>
<!-- 遍历数组(数组里面是对象) -->
<!-- :key的作用:帮助Vue区分不同的元素,从而提高性能 -->
<li :key='item.id' v-for='(item, index) in myFruits'>
<span>{{item.ename}}</span>
<span>-----</span>
<span>{{item.cname}}</span>
</li>
</ul>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
循环结构-遍历数组
*/
var vm = new Vue({
el: '#app',
data: {
fruits: ['apple', 'orange', 'banana'],
myFruits: [{
id: 1,
ename: 'apple',
cname: '苹果'
},{
id: 2,
ename: 'orange',
cname: '橘子'
},{
id: 3,
ename: 'banana',
cname: '香蕉'
}]
}
});
</script>
</body>
</html>
打印结果如下:
② v-for遍历对象
语法:
<div v-for='(value, key, index) in object'></div>
/*
循环结构-遍历对象
v 代表对象的 value
k 代表对象的 key
i 代表 index
*/
<div v-for='(v,k,i) in obj'>{{v + '---' + k + '---' + i}}</div>
<script>
new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
],
obj: {
uname: 'zhangsan',
age: 13,
gender: 'female'
}
}
})
</script>
③ :key 的作用
-
:key
用来给每个节点做一个唯一标识,主要是为了高效的更新虚拟DOM
<ul>
// :key的作用:帮助Vue区分不同的元素,从而提高性能
<li v-for="item in items" :key="item.id">...</li>
</ul>
④ v-if 和 v-for同时使用
- 永远不要在同一个元素上同时使用 v-if 和 v-for,建议使用计算属性替代
- 当它们处于同一节点,v-if 的优先级比 v-for 更高,这意味着 v-if 将没有权限访问 v-for 里面的变量
<div v-if='value==12' v-for='(value, key, index) in object'></div>
8 - 案例:Tab选项卡
- 实现静态UI效果
用传统的方式实现标签结构和样式 - 基于数据重构UI效果
将静态的结构和样式重构为基于Vue模板语法的形式
处理事件绑定和js控制逻辑 - 声明式编程
模板的结构和最终显示的效果基本一致
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.tab ul {
overflow: hidden;
padding: 0;
margin: 0;
}
.tab ul li {
box-sizing: border-box;
padding: 0;
float: left;
width: 100px;
height: 45px;
line-height: 45px;
list-style: none;
text-align: center;
border-top: 1px solid blue;
border-right: 1px solid blue;
cursor
}
.tab ul li:first-child {
border-left: 1px solid blue;
}
.tab ul li.active {
background-color: orange;
}
.tab div {
width: 500px;
height: 300px;
display: none;
text-align: center;
font-size: 30px;
line-height: 300px;
border: 1px solid blue;
border-top: 0px;
}
.tab div.current {
display: block;
}
</style>
</head>
<body>
// Vue模板
<div id="app">
<div class="tab">
<ul>
// 上面的li
// change(index)里面的索引实际上就是 v-for='(item,index) in list 里面的index
<li v-for='(item,index) in list' :key='item.id' v-on:click='change(index)' :class='currentIndex==index?"active":""'>{{item.title}}</li>
</ul>
// 下面的div
<div v-for='(item, index) in list' :key='item.id' :class='currentIndex==index?"current":""'>
<img :src="item.path">
</div>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
currentIndex: 0, // 选项卡当前的索引
list: [{
id: 1,
title: 'apple',
path: 'img/apple.png'
},{
id: 2,
title: 'orange',
path: 'img/orange.png'
},{
id: 3,
title: 'lemon',
path: 'img/lemon.png'
}]
},
methods: {
change: function(index){
// 在这里实现选项卡切换操作:本质就是操作类名
// 如何操作类名?就是通过currentIndex,currentIndex改变了,类名也会改变
this.currentIndex = index;
}
}
});
</script>
</body>
</html>