API文档

Vue模版语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 插值表达式 -->
<div id="app">
<div>{{msg}}</div>
<!-- 输出hello world! -->
<div>{{msg+123}}</div>
<!-- 输出hello world!123 -->
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// 模型数据(值为一个对象)
msg: 'hello world!'
}
});
</script>

v-cloak

如上插值表达式会出现闪动问题,为解决这一问题,可以使用v-cloak指令:

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
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
/* 加入该样式 */

[v-cloak] {
display: none;
}
</style>
</head>

<body>
<div id="app">
<!-- 添加v-cloak -->
<div v-cloak>{{msg}}</div>
<!-- 输出hello world! -->
<div v-cloak>{{msg+123}}</div>
<!-- 输出hello world!123 -->
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// 模型数据(值为一个对象)
msg: 'hello world!'
}
});
</script>
</body>

v-text(推荐)

1
2
<!-- 输出和上面一样,且无闪动(推荐) -->
<div v-text='msg'></div>

v-html(可加入样式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 有安全隐患 -->
<div id="app">
<!-- 添加v-cloak -->
<!-- 输出hello world! -->
<div v-cloak>{{msg}}</div>
<!-- 输出和上面一样,且无闪动(推荐) -->
<div v-text='msg'></div>
<!-- 同样输出,但加上了样式 -->
<div v-html='msg1'></div>

</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// 模型数据(值为一个对象)
msg: 'hello world!',
msg1: '<h1>hello world!</h1>'
}
});
</script>

v-pre

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

数据响应式

如何理解响应式:

  • html5 中的响应式(屏幕尺寸的变化导致样式的变化)

  • 数据的响应式(数据的变化导致页面内容的变化)

什么是数据绑定:

  • 数据绑定:将数据填充到标签中

v-once 只编译一次:

  • 显示内容之后不再具有响应式功能(不会随数据改变而再改变)

双向绑定

1
2
3
4
5
<div id="app">
<div v-cloak>{{msg}}</div>
<!-- input页面和数据双向绑定,input值变化,上面也会变化 -->
<input type="text" v-model="msg">
</div>

MVVM设计思想

  • M(model) (数据对象等)
  • V(view) (页面显示)
  • VM(View Model) (处理M、V之间的关系)
Snipaste_2021-07-30_21-24-06.jpg

事件绑定

  • v-on指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<div>{{num}}</div>
<!-- 点击后进行累加 -->
<!-- <button v-on:click='num++'>点击</button> -->
<!-- 上面语法的简写 -->
<button @click='num++'>点击</button>
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// 模型数据(值为一个对象)
num: 0
}
});
</script>
  • 事件函数的调用(两种方式)
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>
<!-- 点击后进行累加 -->
<!-- 第一种方式 -->
<!-- <button @click='add'>点击</button> -->
<!-- 第二种方式 -->
<button @click='add()'>点击</button>
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// 模型数据(值为一个对象)
num: 0
},
methods: {
add: function() {
// 需要加this,否则会出错;thia指的是vm实例本身
this.num++;
}
}
});
</script>
  • 事件函数参数传递
1
2
<button v-on:click='say("hi",$event)'>Say hi</button>
<!-- $event是固定名称,传递该事件到参数 -->
  • .stop阻止冒泡
1
<a v-on:click.stop="handle"> 跳转 </a>
  • .prevent阻止默认行为
1
<a v-on:click.prevent="handle"> 跳转 </a>
  • 按键修饰符
1
2
3
4
<!-- 按回车键触发 -->
<input v-on:keyup.enter='submit'>
<!-- 按esc键触发 -->
<input v-on:keyup.delete='handle'>

属性绑定

  • v-bind 指令用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<!-- <a v-bind:href="url">百度</a> -->
<!-- 简写 -->
<a :href="url">百度</a>
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
url: 'http://www.baidu.com'
}
});
</script>
  • v-model的低层实现原理分析
1
<input v-bind:value="msg" v-on:input="msg=$event.target.value">

样式绑定

class绑定

  • 对象语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<div v-bind:class='{active:isActive}'></div>
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
isActive: true
}
});
</script>
  • 数组语法

    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
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    /* 样式1 */
    .active {
    width: 100px;
    height: 100px;
    }
    /* 样式2 */
    .error {
    background-color: orange;
    }
    </style>
    </head>
    <body>
    <div id="app">
    <!-- 数组形式的两个类 -->
    <div v-bind:class='[ActiveClass,ErrorClass]'></div>
    </div>
    <!-- 引入vue.js -->
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
    var vm = new Vue({
    // el为元素挂载位置,为css选择器或dom元素
    el: '#app',
    data: {
    ActiveClass: 'active',
    ErrorClass: 'error'
    }
    });
    </script>
    </body>
  • 细节优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    <!-- 混合使用 -->
<div id="app">
<!-- 数组形式的两个类 -->
<div v-bind:class='[ActiveClass,ErrorClass,{text: isTest}]'></div>
<!-- 简化方法:<div v-bind:class='arrClass'></div> -->
</div>
<!-- 引入vue.js -->
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
// arrClass: ['acrive','error'],
ActiveClass: 'active',
ErrorClass: 'error',
isTest: true
}
});
</script>
</body>

style绑定

  • 对象语法
1
2
<div v-bind:style="{ color: activeColor, fontSize: fontSize }"></div>
<!-- 对activeColor进行赋值,方法如class绑定;也可以用别名代替,再在data中操作 -->
  • 数组语法
1
<div v-bind:style="[baseStyles, overridingStyles]"></div>

分支循环结构

  • v-if/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
<div id="app">
<!-- 当score>=90时显示优秀 -->
<div v-if='score>=90'>优秀</div>
<!-- 当score为80~90时显示良好 -->
<div v-else-if='score>=80&&score<90'>良好</div>
<!-- 当score为80以下时显示一般 -->
<div v-else='score<80'>一般</div>
<!-- 当flag为true时显示,为false时隐藏 -->
<div v-show='flag'>123</div>
<!-- 区别:v-show时,即使隐藏也会存在div(display=none),会渲染;而v-if则不再有div存在,不会渲染到浏览器 -->
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
// el为元素挂载位置,为css选择器或dom元素
el: '#app',
data: {
score: 95,
flag: false
}
});
</script>
  • v-for
1
2
3
4
<!-- 显示list的元素,以li形式显示 -->
<li v-for='item in list'>{{item}}</li>
<!-- 显示list的元素及下标,以li形式显示 -->
<li v-for='(item,index) in list'>{{item}} + '------' +{{index}}</li>
  • key 的作用:帮助 Vue 区分不同的元素,从而提高性能
1
2
<!-- 可以设置一个唯一的值,例如index -->
<li :key='item.id' v-for='(item,index) in list'>{{item}} + ' '------' {{index}}</li>
  • v-for遍历对象
1
<div v-for='(value, key, index) in object'></div>
  • v-ifv-for 结合使用
1
<div v-if='value==12' v for='(value, key, index) in object'></div>

Vue常用特性

表单基本操作

  • 获取单选框中的值

    • 通过v-model
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     	<!-- 
    1、 两个单选框需要同时通过v-model 双向绑定 一个值
    2、 每一个单选框必须要有value属性 且value 值不能一样
    3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据

    gender 的值就是选中的值,我们只需要实时监控他的值就可以了
    -->
    <input type="radio" id="male" value="1" v-model='gender'>
    <label for="male">男</label>

    <input type="radio" id="female" value="2" v-model='gender'>
    <label for="female">女</label>

    <script>
    new Vue({
    data: {
    // 默认会让当前的 value 值为 2 的单选框选中
    gender: 2,
    },
    })

    </script>
  • 获取复选框中的值

    • 通过v-model
    • 和获取单选框中的值一样
    • 复选框 checkbox 这种的组合时 data 中的 hobby 我们要定义成数组 否则无法实现多选
    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
    	<!-- 
    1、 复选框需要同时通过v-model 双向绑定 一个值
    2、 每一个复选框必须要有value属性 且value 值不能一样
    3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据

    hobby 的值就是选中的值,我们只需要实时监控他的值就可以了
    -->

    <div>
    <span>爱好:</span>
    <input type="checkbox" id="ball" value="1" v-model='hobby'>
    <label for="ball">篮球</label>
    <input type="checkbox" id="sing" value="2" v-model='hobby'>
    <label for="sing">唱歌</label>
    <input type="checkbox" id="code" value="3" v-model='hobby'>
    <label for="code">写代码</label>
    </div>
    <script>
    new Vue({
    data: {
    // 默认会让当前的 value 值为 2 和 3 的复选框选中
    hobby: ['2', '3'],
    },
    })
    </script>
  • 获取下拉框和文本框中的值

    • 通过v-model
    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
       <div>
    <span>职业:</span>
    <!--
    1、 需要给select 通过v-model 双向绑定 一个值
    2、 每一个option 必须要有value属性 且value 值不能一样
    3、 当某一个option选中的时候 v-model 会将当前的 value值 改变 data 中的 数据
    occupation 的值就是选中的值,我们只需要实时监控他的值就可以了
    -->
    <!-- multiple 多选 -->
    <select v-model='occupation' multiple>
    <option value="0">请选择职业...</option>
    <option value="1">教师</option>
    <option value="2">软件工程师</option>
    <option value="3">律师</option>
    </select>
    <!-- textarea 是 一个双标签 不需要绑定value 属性的 -->
    <textarea v-model='desc'></textarea>
    </div>
    <script>
    new Vue({
    data: {
    // 默认会让当前的 value 值为 2 和 3 的下拉框选中
    occupation: ['2', '3'],
    desc: 'nihao'
    },
    })
    </script>

表单修饰符

  • .number 转换为数值

    • 注意点:
    • 当开始输入非数字的字符串时,因为Vue无法将字符串转换成数值
    • 所以属性值将实时更新成相同的字符串。即使后面输入数字,也将被视作字符串。
  • .trim 自动过滤用户输入的首尾空白字符

    • 只能去掉首尾的 不能去除中间的空格
  • .lazy 将input事件切换成change事件

    • .lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上
  • 在失去焦点 或者 按下回车键时才更新

    1
    2
    3
    4
    5
    6
    7
    8
    <!-- 自动将用户的输入值转为数值类型 -->
    <input v-model.number="age" type="number">

    <!--自动过滤用户输入的首尾空白字符 -->
    <input v-model.trim="msg">

    <!-- 在“change”时而非“input”时更新 -->
    <input v-model.lazy="msg" >

自定义指令

Vue.directive 注册全局指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 
使用自定义的指令,只需在对用的元素中,加上'v-'的前缀形成类似于内部指令'v-if','v-text'的形式。
-->
<input type="text" v-focus>
<script>
// 注意点:
// 1、 在自定义指令中 如果以驼峰命名的方式定义 如 Vue.directive('focusA',function(){})
// 2、 在HTML中使用的时候 只能通过 v-focus-a 来使用

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。 其中 el为dom元素
inserted: function (el) {
// 聚焦元素
el.focus();
}
});
new Vue({
  el:'#app'
});
</script>

Vue.directive 注册全局指令 带参数

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
<input type="text" v-color='msg'>
<script type="text/javascript">
/*
自定义指令-带参数
bind - 只调用一次,在指令第一次绑定到元素上时候调用

*/
Vue.directive('color', {
// bind声明周期, 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
// el 为当前自定义指令的DOM元素
// binding 为自定义的函数形参 通过自定义属性传递过来的值 存在 binding.value 里面
bind: function(el, binding){
// 根据指令的参数设置背景色
// console.log(binding.value.color)
el.style.backgroundColor = binding.value.color;
}
});
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'blue'
}
}
});
</script>

自定义 局部指令

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
<input type="text" v-color='msg'>
<input type="text" v-focus>
<script type="text/javascript">
/*
自定义指令-局部指令
*/
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'red'
}
},
//局部指令,需要定义在 directives 的选项
directives: {
color: {
bind: function(el, binding){
el.style.backgroundColor = binding.value.color;
}
},
focus: {
inserted: function(el) {
el.focus();
}
}
}
});
</script>

计算属性

计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存

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
<!-- 让模版更加简洁,且会进行缓存,提高性能 -->
<div id="app">
<!--
当多次调用 reverseString 的时候
只要里面的 num 值不改变 他会把第一次计算的结果直接返回
直到data 中的num值改变 计算属性才会重新发生计算
-->
<div>{{reverseString}}</div>
<div>{{reverseString}}</div>
<!-- 调用methods中的方法的时候 他每次会重新调用 -->
<div>{{reverseMessage()}}</div>
<div>{{reverseMessage()}}</div>
</div>
<script type="text/javascript">
/*
计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
*/
var vm = new Vue({
el: '#app',
data: {
msg: 'Nihao',
num: 100
},
methods: {
reverseMessage: function(){
console.log('methods')
return this.msg.split('').reverse().join('');
}
},
//computed 属性 定义 和 data 已经 methods 平级
computed: {
// reverseString 这个是我们自己定义的名字
reverseString: function(){
console.log('computed')
var total = 0;
// 当data 中的 num 的值改变的时候 reverseString 会自动发生计算
for(var i=0;i<=this.num;i++){
total += i;
}
// 这里一定要有return 否则 调用 reverseString 的 时候无法拿到结果
return total;
}
}
});
</script>

侦听器

  • 侦听器的应用场景

    数据变化时执行异步或开销较大的操作。数据一旦发生变化就通知侦听器所绑定方法。

  • 侦听器的用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    watch: {
    firstName: function(val){
    // val表示变化之后的值
    this.fullName = val + this.lastName;
    },
    lastName: function(val) {
    this.fullName = this.firstName + val;
    }
    }

过滤器

  • 过滤器的作用

    格式化数据,比如将字符串格式化为首字母大写,将日期格式化为指定的格式等。

  • 自定义过滤器

    1
    2
    3
    Vue.filter((‘过滤器名称 ’, function(){
    //过滤器业务逻辑
    })
  • 过滤器使用

1
2
3
4
5
6
<!-- msg使用upper过滤器 -->
<div>{{msg | upper}}</div>
<!-- msg使用upper过滤器后再用lower过滤器 -->
<div>{{msg | upper | lower}}</div>
<!-- 属性使用过滤器 -->
<div v-bind:id=“id | formatId"></div>
  • 局部过滤器
1
2
3
4
5
filters:{
capitalize: function(val){

}
}
  • 带参数的过滤器
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
·<div id="box">
<!--
filterA 被定义为接收三个参数的过滤器函数。
其中 message 的值作为第一个参数,
普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
-->
{{ message | filterA('arg1', 'arg2') }}
</div>
<script>
// 在过滤器中 第一个参数 对应的是 管道符前面的数据 n 此时对应 message
// 第2个参数 a 对应 实参 arg1 字符串
// 第3个参数 b 对应 实参 arg2 字符串
Vue.filter('filterA',function(n,a,b){
if(n<10){
return n+a;
}else{
return n+b;
}
});

new Vue({
el:"#box",
data:{
message: "哈哈哈"
}
})

</script>

组件化开发

组件注册

  • 全局组件注册
    • data必须是一个函数而不是一个对象
    • 组件模板内容必须是单个根元素,即无兄弟元素
    • 组件模板内容可以是模板字符串(注意驼峰命名不能在普通标签中使用,只能用短横线命名法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<!-- 组件使用 -->
<button-counter></button-counter>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
// 组件注册
Vue.component('button-counter', {
// 数据函数
data: function() {
return {
count: 0
}
},
// 模版
template: '<button @click="count++">{{count}}</button>'
});
var vm = new Vue({
el: '#app',
data: {
msg: '111'
}
});
</script>
  • 局部组件注册
1
2
3
4
5
6
7
8
9
10
11
var ComponentA = { /* ... */ };
var ComponentB = { /* ... */ };
var ComponentC = { /* ... */ };
new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB,
'component-c': ComponentC,
}
});

调试工具

Devtools:https://github.com/vuejs/devtools

Vue组件之间传值

父组件向子组件传值

  • 父组件发送的形式是以属性的形式绑定值到子组件身上。
  • 然后子组件用属性props接收
  • 在props中使用驼峰形式,模板中需要使用短横线的形式
  • 字符串形式的模板中没有这个限制
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
<body>
<div id="app">
<div>{{pmsg}}</div>
<!--1、menu-item 在 APP中嵌套着 故 menu-item 为 子组件 -->
<!-- 给子组件传入一个静态的值 -->
<menu-item title='来自父组件的值'></menu-item>
<!-- 2、 需要动态的数据的时候 需要属性绑定的形式设置 此时 ptitle 来自父组件data 中的数据 .
传的值可以是数字、对象、数组等等
-->
<menu-item :title='ptitle' content='hello'></menu-item>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('menu-item', {
// 3、 子组件用属性props接收父组件传递过来的数据
props: ['title', 'content'],
data: function() {
return {
msg: '子组件本身的数据'
}
},
template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
});
var vm = new Vue({
el: '#app',
data: {
pmsg: '父组件中内容',
ptitle: '动态绑定属性'
}
});
</script>
</body>

子组件向父组件传值

  • 子组件用$emit()触发事件
  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
  • 父组件用v-on监听子组件的事件
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
<div id="app">
<div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
<!-- 2 父组件用v-on 监听子组件的事件
这里 enlarge-text 是从 $emit 中的第一个参数对应 handle 为对应的事件处理函数
-->
<menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
子组件向父组件传值-携带参数
*/

Vue.component('menu-item', {
props: ['parr'],
template: `
<div>
<ul>
<li :key='index' v-for='(item,index) in parr'>{{item}}</li>
</ul>
### 1、子组件用$emit()触发事件
### 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
<button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
<button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
pmsg: '父组件中内容',
parr: ['apple', 'orange', 'banana'],
fontSize: 10
},
methods: {
handle: function(val) {
// 扩大字体大小
this.fontSize += val;
}
}
});
</script>

兄弟之间的传递

  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    • 提供事件中心 var hub = new Vue()
  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
  • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
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
<div id="app">
<div>父组件</div>
<div>
<button @click='handle'>销毁事件</button>
</div>
<test-tom></test-tom>
<test-jerry></test-jerry>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
兄弟组件之间数据传递
*/
//1、 提供事件中心
var hub = new Vue();

Vue.component('test-tom', {
data: function() {
return {
num: 0
}
},
template: `
<div>
<div>TOM:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function() {
//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件
hub.$emit('jerry-event', 2);
}
},
mounted: function() {
// 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on(方法名
hub.$on('tom-event', (val) => {
this.num += val;
});
}
});
Vue.component('test-jerry', {
data: function() {
return {
num: 0
}
},
template: `
<div>
<div>JERRY:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function() {
//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件
hub.$emit('tom-event', 1);
}
},
mounted: function() {
// 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
hub.$on('jerry-event', (val) => {
this.num += val;
});
}
});
var vm = new Vue({
el: '#app',
data: {

},
methods: {
handle: function() {
//4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
hub.$off('tom-event');
hub.$off('jerry-event');
}
}
});
</script>

组件插槽

匿名插槽

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
<div id="app">
<!-- 这里的所有组件标签中嵌套的内容会替换掉slot 如果不传值 则使用 slot 中的默认值 -->
<alert-box>有bug发生</alert-box>
<alert-box>有一个警告</alert-box>
<alert-box></alert-box>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
组件插槽:父组件向子组件传递内容
*/
Vue.component('alert-box', {
template: `
<div>
<strong>ERROR:</strong>
<!-- 当组件渲染的时候,这个 <slot> 元素将会被替换为“组件标签中嵌套的内容”。-->
<!-- 插槽内可以包含任何模板代码,包括 HTML -->
<slot>默认内容</slot>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {

}
});
</script>

具名插槽

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
<div id="app">
<base-layout>
<!-- 2、 通过slot属性来指定, 这个slot的值必须和下面slot组件得name值对应上
如果没有匹配到 则放到匿名的插槽中 -->
<p slot='header'>标题信息</p>
<p>主要内容1</p>
<p>主要内容2</p>
<p slot='footer'>底部信息信息</p>
</base-layout>

<base-layout>
<!-- 注意点:template临时的包裹标签最终不会渲染到页面上 -->
<template slot='header'>
<p>标题信息1</p>
<p>标题信息2</p>
</template>
<p>主要内容1</p>
<p>主要内容2</p>
<template slot='footer'>
<p>底部信息信息1</p>
<p>底部信息信息2</p>
</template>
</base-layout>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
具名插槽
*/
Vue.component('base-layout', {
template: `
<div>
<header>
### 1、 使用 <slot> 中的 "name" 属性绑定元素 指定当前插槽的名字
<slot name='header'></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
### 注意点:
### 具名插槽的渲染顺序,完全取决于模板,而不是取决于父组件中元素的顺序
<slot name='footer'></slot>
</footer>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {

}
});
</script>

作用域插槽

  • 父组件对子组件加工处理
  • 既可以复用子组件的slot,又可以使slot内容不一致
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
<div id="app">
<!--
1、当我们希望li 的样式由外部使用组件的地方定义,因为可能有多种地方要使用该组件,
但样式希望不一样 这个时候我们需要使用作用域插槽

-->
<fruit-list :list='list'>
<!-- 2、 父组件中使用了<template>元素,而且包含scope="slotProps",
slotProps在这里只是临时变量
--->
<template slot-scope='slotProps'>
<strong v-if='slotProps.info.id==3' class="current">
{{slotProps.info.name}}
</strong>
<span v-else>{{slotProps.info.name}}</span>
</template>
</fruit-list>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
作用域插槽
*/
Vue.component('fruit-list', {
props: ['list'],
template: `
<div>
<li :key='item.id' v-for='item in list'>
<slot :info='item'>{{item.name}}</slot>
</li>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
list: [{
id: 1,
name: 'apple'
}, {
id: 2,
name: 'orange'
}, {
id: 3,
name: 'banana'
}]
}
});
</script>

Vue前端交互

Promise

  • 主要解决异步深层嵌套的问题
  • promise 提供了简洁的API 使得异步操作更加容易
1
2
3
4
5
6
7
8
9
var p=new Promise(function(resolve,reject){
// 成功时调用resolve
// 失败时调用reject
});
p.then(function(ret){
// 从resolve得到正常结果
},function(ret){
// 从reject得到错误消息
});

基于Promise发送Ajax请求

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
<script type="text/javascript">
/*
基于Promise发送Ajax请求
*/
function queryData(url) {
# 1.1 创建一个Promise实例
var p = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState != 4) return;
if(xhr.readyState == 4 && xhr.status == 200) {
# 1.2 处理正常的情况
resolve(xhr.responseText);
}else{
# 1.3 处理异常情况
reject('服务器错误');
}
};
xhr.open('get', url);
xhr.send(null);
});
return p;
}
# 注意: 这里需要开启一个服务
# 在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了
queryData('http://localhost:3000/data')
.then(function(data){
console.log(data)
# 1.4 想要继续链式编程下去 需要 return
return queryData('http://localhost:3000/data1');
})
.then(function(data){
console.log(data);
return queryData('http://localhost:3000/data2');
})
.then(function(data){
console.log(data)
});
</script>

Promise 基本API

实例方法

.then()

  • 得到异步任务正确的结果

.catch()

  • 获取异常信息

.finally()

  • 成功与否都会执行(不是正式标准)
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
<script type="text/javascript">
/*
Promise常用API-实例方法
*/
// console.dir(Promise);
function foo() {
return new Promise(function(resolve, reject){
setTimeout(function(){
// resolve(123);
reject('error');
}, 100);
})
}
// foo()
// .then(function(data){
// console.log(data)
// })
// .catch(function(data){
// console.log(data)
// })
// .finally(function(){
// console.log('finished')
// });

// --------------------------
// 两种写法是等效的
foo()
.then(function(data){
# 得到异步任务正确的结果
console.log(data)
},function(data){
# 获取异常信息
console.log(data)
})
# 成功与否都会执行(不是正式标准)
.finally(function(){
console.log('finished')
});
</script>

静态方法

.all()

  • Promise.all方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve转换为一个promise)。它的状态由这三个promise实例决定

.race()

  • Promise.race方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilledrejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数
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
<script type="text/javascript">
/*
Promise常用API-实例方法
*/
// console.dir(Promise);
function foo() {
return new Promise(function(resolve, reject){
setTimeout(function(){
// resolve(123);
reject('error');
}, 100);
})
}
// foo()
// .then(function(data){
// console.log(data)
// })
// .catch(function(data){
// console.log(data)
// })
// .finally(function(){
// console.log('finished')
// });

// --------------------------
// 两种写法是等效的
foo()
.then(function(data){
# 得到异步任务正确的结果
console.log(data)
},function(data){
# 获取异常信息
console.log(data)
})
# 成功与否都会执行(不是正式标准)
.finally(function(){
console.log('finished')
});
</script>

fetch

  • Fetch API是新的ajax解决方案 Fetch会返回Promise
  • fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
  • fetch(url, options).then()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script type="text/javascript">
/*
Fetch API 基本用法
fetch(url).then()
第一个参数请求的路径 Fetch会返回Promise 所以我们可以使用then 拿到请求成功的结果
*/
fetch('http://localhost:3000/fdata').then(function(data){
// text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
return data.text();
}).then(function(data){
// 在这个then里面我们能拿到最终的数据
console.log(data);
})
</script>

fetch API 中的 HTTP 请求

  • fetch(url, options).then()
  • HTTP协议,它给我们提供了很多的方法,如POST,GET,DELETE,UPDATE,PATCH和PUT
    • 默认的是 GET 请求
    • 需要在 options 对象中 指定对应的 method method:请求使用的方法
    • post 和 普通 请求的时候 需要在options 中 设置 请求头 headers 和 body
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
<script type="text/javascript">
/*
Fetch API 调用接口传递参数
*/
#1.1 GET参数传递 - 传统URL 通过url ? 的形式传参
fetch('http://localhost:3000/books?id=123', {
# get 请求可以省略不写 默认的是GET
method: 'get'
})
.then(function(data) {
# 它返回一个Promise实例对象,用于获取后台返回的数据
return data.text();
}).then(function(data) {
# 在这个then里面我们能拿到最终的数据
console.log(data)
});

#1.2 GET参数传递 restful形式的URL 通过/ 的形式传递参数 即 id = 456 和id后台的配置有关
fetch('http://localhost:3000/books/456', {
# get 请求可以省略不写 默认的是GET
method: 'get'
})
.then(function(data) {
return data.text();
}).then(function(data) {
console.log(data)
});

#2.1 DELETE请求方式参数传递 删除id 是 id=789
fetch('http://localhost:3000/books/789', {
method: 'delete'
})
.then(function(data) {
return data.text();
}).then(function(data) {
console.log(data)
});

#3 POST请求传参
fetch('http://localhost:3000/books', {
method: 'post',
# 3.1 传递数据
body: 'uname=lisi&pwd=123',
# 3.2 设置请求头
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function(data) {
return data.text();
}).then(function(data) {
console.log(data)
});

# POST请求传参
fetch('http://localhost:3000/books', {
method: 'post',
body: JSON.stringify({
uname: '张三',
pwd: '456'
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(data) {
return data.text();
}).then(function(data) {
console.log(data)
});

# PUT请求传参 修改id 是 123 的
fetch('http://localhost:3000/books/123', {
method: 'put',
body: JSON.stringify({
uname: '张三',
pwd: '789'
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(data) {
return data.text();
}).then(function(data) {
console.log(data)
});
</script>

fetchAPI 中 响应格式

  • 用fetch来获取数据,如果响应正常返回,我们首先看到的是一个response对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如JSONBLOB或者TEXT等等。

axios

  • 基于promise用于浏览器和node.js的http客户端
  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和响应
  • 自动转换JSON数据
  • 能转换请求和响应数据

axios基础用法

  • get和 delete请求传递参数
    • 通过传统的url 以 ? 的形式传递参数
    • restful 形式传递参数
    • 通过params 形式传递参数
  • post 和 put 请求传递参数
    • 通过选项传递参数
    • 通过 URLSearchParams 传递参数
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
   # 1. 发送get 请求 
axios.get('http://localhost:3000/adata').then(function(ret){
# 拿到 ret 是一个对象 所有的对象都存在 ret 的data 属性里面
// 注意data属性是固定的用法,用于获取后台的实际数据
// console.log(ret.data)
console.log(ret)
})
# 2. get 请求传递参数
# 2.1 通过传统的url 以 ? 的形式传递参数
axios.get('http://localhost:3000/axios?id=123').then(function(ret){
console.log(ret.data)
})
# 2.2 restful 形式传递参数
axios.get('http://localhost:3000/axios/123').then(function(ret){
console.log(ret.data)
})
# 2.3 通过params 形式传递参数
axios.get('http://localhost:3000/axios', {
params: {
id: 789
}
}).then(function(ret){
console.log(ret.data)
})
#3 axios delete 请求传参 传参的形式和 get 请求一样
axios.delete('http://localhost:3000/axios', {
params: {
id: 111
}
}).then(function(ret){
console.log(ret.data)
})

# 4 axios 的 post 请求
# 4.1 通过选项传递参数
axios.post('http://localhost:3000/axios', {
uname: 'lisi',
pwd: 123
}).then(function(ret){
console.log(ret.data)
})
# 4.2 通过 URLSearchParams 传递参数
var params = new URLSearchParams();
params.append('uname', 'zhangsan');
params.append('pwd', '111');
axios.post('http://localhost:3000/axios', params).then(function(ret){
console.log(ret.data)
})

#5 axios put 请求传参 和 post 请求一样
axios.put('http://localhost:3000/axios/123', {
uname: 'lisi',
pwd: 123
}).then(function(ret){
console.log(ret.data)
})

axios全局配置

1
2
3
4
5
6
7
8
9
#  配置公共的请求头 
axios.defaults.baseURL = 'https://api.example.com';
# 配置 超时时间
axios.defaults.timeout = 2500;
# 配置公共的请求头
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
# 配置公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

axios拦截器

  • 请求拦截器
    • 请求拦截器的作用是在请求发送前进行一些操作
      • 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
  • 响应拦截器
    • 响应拦截器的作用是在接收到响应后进行一些操作
      • 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 请求拦截器 
axios.interceptors.request.use(function(config) {
console.log(config.url)
# 1.1 任何请求都会经过这一步 在发送请求之前做些什么
config.headers.mytoken = 'nihao';
# 1.2 这里一定要return 否则配置不成功
return config;
}, function(err){
#1.3 对请求错误做点什么
console.log(err)
})
#2. 响应拦截器
axios.interceptors.response.use(function(res) {
#2.1 在接收响应做些什么
var data = res.data;
return data;
}, function(err){
#2.2 对响应错误做点什么
console.log(err)
})

async 和 await

  • async作为一个关键字放到函数前面

    • 任何一个async函数都会隐式返回一个promise
  • await关键字只能在使用async定义的函数中使用

    • await后面可以直接跟一个 Promise实例对象
      
      1
      2
      3
          
      + ```auto
      await函数不能单独使用
  • async/await 让异步代码看起来、表现起来更像同步代码

Vue前端路由

路由的概念

路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。
那么url地址和真实的资源之间就有一种对应的关系,就是路由。

  • 后端路由是由服务器端进行实现,并完成资源的分发
  • 前端路由是依靠hash值(锚链接)的变化进行实现
  • 前端路由的基本概念:根据不同的事件来显示不同的页面内容,即事件与事件处理函数之间的对应关系

前端路由的初体验

前端路由是基于hash值的变化进行实现的(比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换)核心实现依靠一个事件,即监听hash值变化的事件

1
2
3
4
window.onhashchange = function(){
//location.hash可以获取到最新的hash值
location.hash
}

前端路由实现tab栏切换(案例)

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
<!-- 被 vue 实例控制的 div 区域 -->
<div id="app">
<!-- 切换组件的超链接 -->
<a href="#/zhuye">主页</a>
<a href="#/keji">科技</a>
<a href="#/caijing">财经</a>
<a href="#/yule">娱乐</a>

<!-- 根据 :is 属性指定的组件名称,把对应的组件渲染到 component 标签所在的位置 -->
<!-- 可以把 component 标签当做是【组件的占位符】 -->
<component :is="comName"></component>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
// #region 定义需要被切换的 4 个组件
// 主页组件
const zhuye = {
template: '<h1>主页信息</h1>'
}

// 科技组件
const keji = {
template: '<h1>科技信息</h1>'
}

// 财经组件
const caijing = {
template: '<h1>财经信息</h1>'
}

// 娱乐组件
const yule = {
template: '<h1>娱乐信息</h1>'
}
// #endregion

// #region vue 实例对象
const vm = new Vue({
el: '#app',
data: {
comName: 'zhuye'
},
// 注册私有组件
components: {
zhuye,
keji,
caijing,
yule
}
})
// #endregion

// 监听 window 的 onhashchange 事件,根据获取到的最新的 hash 值,切换要显示的组件的名称
window.onhashchange = function() {
// 通过 location.hash 获取到最新的 hash 值
console.log(location.hash);
switch (location.hash.slice(1)) {
case '/zhuye':
vm.comName = 'zhuye'
break
case '/keji':
vm.comName = 'keji'
break
case '/caijing':
vm.comName = 'caijing'
break
case '/yule':
vm.comName = 'yule'
break
}
}
</script>

Vue Router

它是一个Vue.js官方提供的路由管理器。是一个功能更加强大的前端路由器,推荐使用。Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发。Vue Router依赖于Vue,所以需要先引入Vue,再引入Vue Router.

基本使用

  • 导入js文件

    1
    2
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/vue-router.js"></script>
  • 添加路由链接,<router-link>是路由中提供的标签,默认会被渲染为a标签,to属性默认被渲染为href属性,
    to属性的值会被渲染为#开头的hash地址。

    1
    2
    <router-link to="/user">User</router-link>
    <router-link to="/register">Register</router-link>
  • 添加路由填充位(路由占位符)

    1
    <router-view></router-view>
  • 定义路由组件

    1
    2
    3
    4
    5
    6
    const User = {
    template: '<h1>User组件</h1>'
    };
    const Register = {
    template: '<h1>Register组件</h1>'
    };
  • 配置路由规则并创建路由实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const router = new VueRouter({
    // 所有路由规则
    routes: [{
    path: "/user",
    component: User
    }, {
    path: '/register',
    component: Register
    }]
    });
  • 将路由挂载到Vue实例中

    1
    2
    3
    4
    5
    6
    const vm = new Vue({
    el: '#app',
    data: {},
    // 挂载路由实例对象
    router: router
    });
  • 总体代码

    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
    <!DOCTYPE html>

    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/vue-router.js"></script>
    </head>

    <body>
    <!-- 被 vue 实例控制的 div 区域 -->
    <div id="app">
    <router-link to="/user">User</router-link>
    <router-link to="/register">Register</router-link>

    <!-- 路由占位符 -->
    <router-view>

    </router-view>
    </div>
    <script>
    // 定义两个组件
    const User = {
    template: '<h1>User组件</h1>'
    };
    const Register = {
    template: '<h1>Register组件</h1>'
    };
    // 创建路由实例对象
    const router = new VueRouter({
    // 所有路由规则
    routes: [{
    path: "/user",
    component: User
    }, {
    path: '/register',
    component: Register
    }]
    });
    const vm = new Vue({
    el: '#app',
    data: {},
    // 挂载路由实例对象
    router: router
    });
    </script>
    </body>

    </html>

路由重定向

在路由规则中添加一条路由规则即可,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const router = new VueRouter({
// 所有路由规则
routes: [{
path: "/",
redirect: "/user"
}, {
path: "/user",
component: User
}, {
path: '/register',
component: Register
}]
});

嵌套路由

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
<!DOCTYPE html>

<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>

<body>
<!-- 被 vue 实例控制的 div 区域 -->
<div id="app">
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>

<!-- 路由占位符 -->
<router-view>

</router-view>
</div>
<script>
// 定义两个组件
const User = {
template: '<h1>User组件</h1>'
};
// 嵌套路由
const Register = {
template: `<div>
<h1>Register组件</h1>
<hr>
<router-link to="/register/tab1">tab1组件</router-link>
<router-link to="/register/tab2">tab2组件</router-link>
<!-- 子路由组件将会在router-view中显示 -->
<router-view></router-view>
</div>`
};
const tab1 = {
template: `
<h1>tab1组件</h1>`
};
const tab2 = {
template: `
<h1>tab2组件</h1>`
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
routes: [{
path: "/",
redirect: "/user"
}, {
path: "/user",
component: User
}, {
path: '/register',
component: Register,
// children数组记下子路由规则
children: [{
path: '/register/tab1',
component: tab1
}, {
path: '/register/tab2',
component: tab2
}]
}]
});
const vm = new Vue({
el: '#app',
data: {},
// 挂载路由实例对象
router: router
});
</script>
</body>

</html>

动态路由匹配

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
<body>
<!-- 被 vue 实例控制的 div 区域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>

<!-- 路由占位符 -->
<router-view>

</router-view>
</div>
<script>
// 定义两个组件
const User = {
// 获取id
template: '<h1>User组件---id为{{$route.params.id}}</h1>'
};
const Register = {
template: '<h1>Register组件</h1>'
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
routes: [{
// 用id代替相似的参数
path: "/user/:id",
component: User
}, {
path: '/register',
component: Register
}]
});
const vm = new Vue({
el: '#app',
data: {},
// 挂载路由实例对象
router: router
});
</script>
</body>

</html>

补充:

如果使用$route.params.id来获取路径传参的数据不够灵活。我们可以通过props来接收参数。

  • props为布尔型
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
<body>
<!-- 被 vue 实例控制的 div 区域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>

<!-- 路由占位符 -->
<router-view>

</router-view>
</div>
<script>
// 定义两个组件
const User = {
// 获取id
template: '<h1>User组件---id为{{$route.params.id}}</h1>'
};
const Register = {
template: '<h1>Register组件</h1>'
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
routes: [{
// 用id代替相似的参数
path: "/user/:id",
component: User
}, {
path: '/register',
component: Register
}]
});
const vm = new Vue({
el: '#app',
data: {},
// 挂载路由实例对象
router: router
});
</script>
</body>

</html>
  • props为对象类型
1
2
3
4
5
6
7
8
9
10
11
12
13
var User = { 
props:["username","pwd"],
template:"<div>用户:{{username}}---{{pwd}}</div>"
}

var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过/:参数名 的形式传递参数
//如果props设置为对象,则传递的是对象中的数据给组件
{ path: "/user/:id", component: User,props:{username:"jack",pwd:123} }
]
});
  • props为函数类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var User = { 
props:["username","pwd","id"],
template:"<div>用户:{{id}} -> {{username}}---{{pwd}}</div>"
}

var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过/:参数名 的形式传递参数
//如果props设置为函数,则通过函数的第一个参数获取路由对象
//并可以通过路由对象的params属性获取传递的参数
//
{ path: "/user/:id", component: User,props:(route)=>{
return {username:"jack",pwd:123,id:route.params.id}
}
}]
});

命名路由

1
2
3
4
5
6
7
8
9
10
11
12
13
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过name属性为路由添加一个别名
{ path: "/user/:id", component: User, name:"user"}
]
});
//添加了别名之后,可以使用别名进行跳转
<router-link to="/user">User</router-link>
<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>

//还可以编程式导航
myRouter.push( { name:'user' , params: {id:123} } )

编程式导航

页面导航的两种方式:

  • 声明式导航:通过点击链接的方式实现的导航
  • 编程式导航:调用js的api方法实现导航,例如location.href导航

Vue-Router中常见的导航方式:

  • this.$router.push(“hash地址”);

  • this.$router.push(“/login”);

  • this.$router.push({ name:’user’ , params: {id:123} });

  • this.$router.push({ path:”/login” });

  • this.$router.push({ path:”/login”,query:{username:”jack”} });

  • this.$router.go( n );//n为数字,参考history.go

  • this.$router.go( -1 );