由于手头有项目压力,需要短时间内入门VUE,时间较赶。所以本文先快速学一遍【黑马程序员-VUE全家桶之VUE基础】这个视频,有时间了再学【千锋教育-Vue2.0+Vue3.0全套教程】的视频。本文标题中的数字表示B站视频内容对应的分P数。

【VUE概述】

渐进式JavaScript框架

可以当成库,也可以当成框架来使用

声明式渲染=>组件系统=>客户端路由=>集中式状态管理(VueX)=>项目构建

官网:http://cn.vuejs.org/v2/guide/

接口:http://cn.vuejs.org/v2/api/

Vue.js 3.0 中文文档(旧版)
Vue.js 3.0 中文文档(新版)

【VUE基本使用】

  • 传统开发模式(原生JS)

    1
    2
    3
    4
    5
    6
    <div id="msd"></div>
    <script type="text/javascript">
    var msg = 'Hello World';
    var div = document.getElementById('msg');
    div.innerHTML = msg;
    </script>
  • 传统开发模式(jQuery)

    1
    2
    3
    4
    5
    6
    <div id="msd"></div>
    <script type="text/javascript" src="js/jquery.js"></script>
    <script type="text/javascript">
    var msg = 'Hello World';
    $('#msg').html(msg);
    </script>
  • VUE开发模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!-- 1. 提供标签用于填充数据 -->
    <div id="app">
    <div>{{msg}}</div>
    </div>

    <!-- 2. 引入vue.js库文件 -->
    <script type="text/javascript" src="js/vue.js"></script>

    <!-- 3. 使用Vue语法做功能 -->
    <!-- 4. 填充Vue提供的数据到标签里 -->
    <script type="text/javascript">
    new Vue({
    el: '#app', //标签选择
    data: { //数据填充
    msg: 'Hello World'
    }
    })
    </script>

  • 可以感觉到使用vue无需操作DOM了,其中:

    1. el是元素的挂载位置(值可以是CSS选择器或者DOM元素)
    2. data是模型数据(值是一个对象)
  • {{}}是vue的差值表达式,可以将数据填充到HTML标签中,插值表达式支持基本的计算操作。

    1
    2
    比如加法        {{1 + 2}}
    或者拼接字符串 {{msg + '----' + 123}}
  • VUE代码运行原理:
    通过编译过程Vue语法->原生语法


【VUE模板语法】(P4~28)

1. 模板语法概述

(1)如何理解前端渲染

  • 前端渲染是什么?是把数据填充到HTML标签中
    比如通过Ajax获取到后台的数据,按照模板进行前端渲染,得到静态的HTML内容

(2)前端渲染的方式

  • 前端渲染的方式有哪些?
    1. 可以原生JS拼接字符串
    2. 可以使用前端模板引擎拼接(如art-template)
    3. 可以使用VUE特有的模板语法
    4. 文档碎片document.createDocumentFragment
    5. 利用es6 ```` 反引号拼接字符串

(3)原生JS拼接字符串

基本上就是将数据以字符串的方式拼接到HTML标签中。

缺点:不同开发人员的代码风格差异很大,随着业务分复杂,后期维护变得困难。

(4)使用前端模板引擎

如基于art-template的代码,与拼接字符串相比,代码明显规范很多,它拥有自己的一套模板语法规则。

优点:大家遵循同样的规则写代码,代码可读性明显提高,方便后期的维护。

缺点:没有专门提供事件的处理机制。

(5)模板语法概览

  1. 差值表达式
  2. 指令
  3. 事件绑定
  4. 属性绑定
  5. 样式绑定
  6. 分支循环结构

2. 指令

(1)什么是指令

  • 什么是指令?
    1. 什么是自定义属性?
    2. 指令的本质就是自定义事件
    3. 指令的格式:以v-开始(比如:v-cloak

刚刚讲过了,vue的差值表达式,可以将数据填充到HTML标签中,插值表达式支持基本的计算操作。

1
2
比如加法        {{1 + 2}}
或者拼接字符串 {{msg + '----' + 123}}

(2)v-cloak指令语法

  • 为什么会有闪烁问题?
    代码加载的时候先加载HTML,把插值语法(花括号)当做HTML内容加载到页面上 当加载完js后才把插值语法迅速替换掉,所以我们会看到闪烁问题

  • 如何解决插值语法的闪烁问题?
    v-cloak指令:https://cn.vuejs.org/v2/api/#v-cloak

  • 使用方法:

    1. 提供样式(方括号的作用类似于选择器)
      1
      2
      3
      [v-cloak] {
      display: none;
      }
    2. 在差值表达式标签中添加指令
      1
      2
      3
      <div v-cloak>
      {{ message }}
      </div>
  • 原理是什么?
    先通过CSS样式隐藏内容,然后在内存中进行值的替换,替换好后再显示最终的结果。

(3)数据绑定指令(数据填充)

数据绑定:就是将数据填充到页面中

v-text

更新元素的 textContent

填充纯文本,相比差值表达式更加简洁,没有闪动问题。

1
2
3
<span v-text="msg"></span>
<!-- 和下面的一样 -->
<span>{{msg}}</span>

v-html

更新元素的 innerHTML

填充HTML片段,但存在安全问题,本网站内部数据可以使用,来自第三方的数据不可以用。

1
<div v-html="html"></div>

注意:在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html,永不用在用户提交的内容上。

v-pre

跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

填充(显示)原始信息,跳过编译过程(分析编译过程)。

1
<span v-pre>{{ this will not be compiled }}</span>

有点类似于在书写Markdown笔记时使用的反引号,用来直接显示原始代码。

(4)数据响应式

如何理解响应式

  1. HTML5中的响应式(屏幕尺寸的变化导致样式的变化)
  2. 数据的响应式(数据的变化导致页面内容的变化)

什么是数据绑定

上面学的数据绑定(将数据填充到页面中)的三个指令v-textv-htmlv-pre默认的是响应式,改值的时候页面内容会自动发生变化。

v-once只编译一次

v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

v-once显示内容之后不再具有响应式功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 单个元素 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 有子元素 -->
<div v-once>
<h1>comment</h1>
<p>{{msg}}</p>
</div>
<!-- 组件 -->
<my-component v-once :comment="msg"></my-component>
<!-- `v-for` 指令-->
<ul>
<li v-for="i in list" v-once>{{i}}</li>
</ul>

应用场景,如果显示的信息后续不需要再修改,可以使用v-once,节省性能。

3. 双向数据绑定

(1)什么是双向数据绑定

  • 什么是双向数据绑定
    1. 当数据发生变化的时候,视图也就发生变化
    2. 当视图发生变化的时候,数据也会跟着同步变化

(2)双向数据绑定分析(v-model)

  • 双向绑定的使用场景
    v-model是一个指令,限制在<input><select><textarea>components(组件)中使用
  • Vue中通过哪一个指令实现双向绑定?
    v-model

双向数据绑定主要用于绑定表单控件上数据:

  1. 用户修改表单数据中的内容时,会影响数据的变化;
  2. 数据变化时,也会影响表单数据中的内容。

用法:https://cn.vuejs.org/v2/api/index.html#v-model

使用案例:页面显示的内容随着输入框输入的内容实时变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<div>{{msg}}</div>
<div>
<input type="text" v-model='msg'>
</div>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app', //标签选择
data: { //数据填充
msg: 'Hello World'
}
})
</script>

(3)MVVM设计思想

  • M、V、VM 分别代表什么?
    1. Model 模型
    2. View 视图(Vue中view即我们的HTML页面)
    3. V-Model 控制器,将数据和视图层建立联系,实现控制逻辑(vm即Vue的实例)

MVVM是VUE框架非常核心的设计思想,理念是“分而治之”。也就是把不同功能的代码放到不同的模块里,然后通过特定的方式建立起关联。如图所示,VM起到了中介作用,把View和Model联系到一起。从视图到模型用的是事件监听,从模型到视图用的是数据绑定。

bgXfRU.jpg


4. 事件绑定

(1)VUE如何处理事件(v-on)

  • Vue中 如何绑定事件?官方文档
    • v-on 指令语法
      1
      <input type="button" v-on:click='num++'/>
    • v-on 简写形式
      1
      <input type="button" @click='num++'/>
    • 案例:点击按钮,数字不断增加
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      <div id="app">
      <div>{{num}}</div>
      </div>

      <div id="app">
      <button v-on:click='num++'>点击(v-on事件绑定)</button>
      <button @click='num++'>点击(v-on指令简写来事件绑定)</button>
      </div>

      <script type="text/javascript" src="js/vue.js"></script>
      <script type="text/javascript">
      var vm = new Vue({
      el: '#app', //标签选择
      data: { //数据填充
      num: 0
      },
      methods: {
      handle: function(){
      num++
      }
      }
      })
      </script>

(2)事件函数的调用方式

  • 事件函数的调用方式:
    • 第一种,直接绑定函数名称
      1
      <button v-on:click='say'>Hello</button>
    • 第二种,调用函数
      1
      <button v-on:click='say()'>Hello</button>
    • 案例:点击按钮,数字不断增加
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      <div id="app">
      <div>{{num}}</div>
      </div>

      <div id="app">
      <button v-on:click='num++'>点击(v-on事件绑定)</button>
      <button @click='num++'>点击(v-on指令简写来事件绑定)</button>
      <button @click='handle'>点击(直接绑定函数名称调用函数)</button>
      <button @click='handle()'>点击(加小括号调用函数)</button>
      </div>

      <script type="text/javascript" src="js/vue.js"></script>
      <script type="text/javascript">
      var vm = new Vue({
      el: '#app', //标签选择
      data: { //数据填充
      num: 0
      },
      //VUE中专门有一个属性methods,用来定义方法,里面可以实现控制逻辑
      methods: {
      handle: function(){
      this.num++; //这里的this指的是该VUE实例对象(vm)
      }
      }
      })
      </script>

(3)事件函数参数传递

我们有时候说“函数”,有时候也说“方法”,其实都是一个意思。

  • 普通参数和事件对象
    1
    <button v-on:click='say("hi",Sevent)'>Say hi</button>
  1. 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数
  2. 如果事件绑定函数调用(),那么对象必须作为最后一个参数显示传递,并且事件的名称必须是$event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<div id="app">
<div>{{num}}</div>
</div>

<div id="app">
<button v-on:click='handle1'>点击1</button>
<!-- 上面没有传递参数 -->
<button v-on:click='handle2(123,456,$event)'>点击2</button>
<!-- 上面传递了参数 -->
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app', //标签选择
data: { //数据填充
num: 0
},
methods: {
handel1: function(event){
console.log(event.taget.innerHTML)
},
handle2: function(p,p1,event){
console.log(p,p1)
console.log(event.taget.innerHTML)
this.num++; //这里的this指的是该VUE实例对象(vm)
}
}
})
</script>

(4)事件修饰符

  • .stop 阻止冒泡

    1
    2
    3
    4
    <a v-on:click.stop="handle">跳转</a>
    <!-- 原生JS
    .stopPropagation();
    -->
  • .prevent 取消默认事件

    1
    2
    3
    4
    <a v-on:click.prevent="handle">跳转</a>
    <!-- 原生JS
    .preventDefault();
    -->
  • .capture

    1
    <!-- 添加事件侦听器时使用 capture 模式。 -->
  • .self

    1
    2
    3
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的,冒泡上来的事件不会触发 -->
    <div v-on:click.self="doThat">...</div>
  • .once

    1
    <!-- 只触发一次回调。 -->
  • .passive

    1
    <!-- (2.3.0) 以 { passive: true } 模式添加侦听器 -->

多个修饰符可以串联书写(注意顺序不同功能也会有差异)。常用事件修饰符更多事件修饰符

(5)按键修饰符

  • .enter

    1
    <input v-on:keyup.enter='submit'>
  • .delete

    1
    <input v-on:keyup.delete='handle'>

常用按键修饰符

(6)自定义按键修饰符

通过全局 config.keyCodes 对象自定义按键修饰符别名:

1
2
3
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
// 意思是当按fi键的时候触发函数

(7)案例:简单计算器

视频教程


5. 属性绑定

  • vue 中怎么操作属性
    1. v-bind 指令被用来响应地更新 HTML 属性
    2. v-bind:href 可以缩写为 :href
  • v-bind 和 v-on的区别
    1. v-bind 绑定属性
    2. v-on 绑定事件

(1)如何动态处理属性(v-bind)

  • v-bind指令语法

    1
    <a v-bind:href='url'>跳转</a>
  • 缩写形式

    1
    <a :href='url'>跳转</a>

(2)v-model的底层实现原理分析

用到了属性绑定(v-bind)和时间绑定(v-on)

1
<input v-bind:value="msg" v-on:input="msg=$event.target.value">
  • 模拟v-model
    1. 第一种方案
      • 通过 v-on监听输入框的输入事件 将输入的值通过事件处理函数存到data中
      • 给输入框通过v-bind 绑定属性 value 把数据渲染到页面上
    2. 第二种方案
      • 通过 v-on监听输入框的输入事件 通过事件对象$event 拿到输入的值 直接存储到data中
      • 给输入框通过v-bind 绑定属性 value 把数据渲染到页面上

6. 样式绑定

(1). class样式处理

  • 对象语法
    <div v-bind:class="{ active: isActive }"></div>
  • 数组语法
    <div v-bind:class="[activeClass, errorClass]"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!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;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{active: isActive,error: isError}">
测试样式
</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: {
isActive: true,
isError: true
},
methods: {
handle: function(){
// 控制isActive的值在true和false之间进行切换
this.isActive = !this.isActive;
this.isError = !this.isError;
}
}
});
</script>
</body>
</html>

(2) style样式处理

  • 对象语法
    <div v-bind:style="{ color: activeColor, fontSize: fontSize }"></div>
  • 数组语法
    <div v-bind:style="[baseStyles, overridingStyles]"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!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;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class='[activeClass, errorClass]'>测试样式</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'
},
methods: {
handle: function(){
this.activeClass = '';
this.errorClass = '';
}
}
});
</script>
</body>
</html>

样式绑定相关语法细节:

  1. 对象绑定和数组绑定可以结合使用
  2. class绑定的值可以简化操作
  3. 默认的class如何处理?默认的class会保留
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!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">
<div v-bind:class='[activeClass, errorClass, {test: isTest}]'>测试样式</div>
<div v-bind:class='arrClasses'></div>
<div v-bind:class='objClasses'></div>
<div class="base" v-bind:class='objClasses'></div>

<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
样式绑定相关语法细节:
1、对象绑定和数组绑定可以结合使用
2、class绑定的值可以简化操作
3、默认的class如何处理?默认的class会保留

*/
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>

7. 分支循环结构

(1)分支结构

  • v-if
  • v-else
  • v-else-if
  • v-show
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!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控制元素是否渲染到页面
  • v-show控制元素是否显示(已经渲染到了页面)

它俩的最终显示效果是一样的,
但如果我们想要的元素渲染出来基本不需要变了,就用v-if;
如果需要频繁显示与隐藏,就用v-show

(3)循环结构(遍历数组)

  • v-for遍历数组
    1
    <li v-for='item in list'>{{item}}</li>
    1
    <li v-for='(item,index) in list'>{{item}} + '---' +{{index}}</li>

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!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>
<li v-for='(item, index) in fruits'>{{item + '---' + index}}</li>
<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>
  • key的作用:帮助Vue区分不同的元素,从而提高性能
    1
    <li :key='item.id' v-for='(item,index) in list'>{{item}} + '---' {{index}}</li>

为了提高性能,我们原则上在遍历的时候都加上key(即使不加也没什么影响),有id值可以用id,没有的话可以用index索引或者其他什么的值(需具有唯一性),来帮助vue进行区分兄弟节点元素

(4)循环结构(遍历对象)

  • v-for遍历对象

    1
    <div v-for='(value, key, index) in object'></div>
  • v-if和v-for结合使用(条件满足时才渲染)

    1
    <div v-if='value==12' v-for='(value, key, index) in object'></div>

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>
<div id="app">
<div v-if='v==13' v-for='(v,k,i) in obj'>{{v + '---' + k + '---' + i}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
// 使用原生js遍历对象
var obj = {
uname: 'lisi',
age: 12,
gender: 'male'
}
for(var key in obj) {
console.log(key, obj[key])
}
/*
使用Vue循环结构遍历对象
*/
var vm = new Vue({
el: '#app',
data: {
obj: {
uname: 'zhangsan',
age: 13,
gender: 'female'
}
}
});
</script>
</body>
</html>

》基础案例-Tab选项卡

1
2
3
4
5
6
7
8
9
10
// Vue模板
var vm = new Vue({ //实例对象vm
el: '#app', //模板
data: { //数据

},
methods: { //JS控制逻辑

}
});

实现步骤:

  1. 静态UI布局(用传统的方式实现)
  2. 重构UI效果(基于Vue模板语法)
  3. JS事件处理(声明式编程:模板的结构和最终显示的效果基本一致)

静态UI布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<div class="tab">
<ul>
<li>苹果</li>
<li>橙子</li>
<li>柠檬</li>
</ul>

<div>
<img src="img/apple.png">
</div>
<div>
<img src="img/orange.png">
</div>
<div>
<img src="img/lemon.png">
</div>
</div>
</div>

完整案例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!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: pointer;
}
.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>
<div id="app">
<div class="tab">
<ul>
<li v-on:click='change(index)' :class='currentIndex==index?"active":""' :key='item.id' v-for='(item,index) in list'>{{item.title}}</li>
</ul>
<div :class='currentIndex==index?"current":""' :key='item.id' v-for='(item, index) in list'>
<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
this.currentIndex = index;
}
}
});
</script>
</body>
</html>

【踩的坑汇总】:

  1. var vm = new Vue,注意左侧新建Vue实例时V要大写,否则报错说vue未定义
  2. :class='currentIndex==index?"active":""',这句话用到了v-bind指令的class属性绑定,后面是JS的三目运算符,格式是条件?语句壹:语句贰
  3. 保持良好书写习惯,遍历时加上:key='item.id'提高Vue的性能
  4. 本例中有点难理解的是v-on:click="change(index)"的传参逻辑

特别感谢: