Axios解决响应结果字符串变为数字的问题

前言

axios

Vue.js 模板语法

Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。

Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。

结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。


插值

文本

数据绑定最常见的形式就是使用

1
{{...}}

(双大括号)的文本插值:

打开 index.html

1
2
3
4
5
6
7
<div id="app"></div>
<!-- built files will be auto injected -->
<div id="vue_det">
<h1>author : {{author}}</h1>
<h1>date : {{date}}</h1>
<h1>{{description()}}</h1>
</div>

打开 src/main.js,这里面放的是当前routerjs脚本的地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 在最后添加 ,因为最上面已经添加了 import Vue from 'vue' 所以就可以直接用了
// eslint-disable-next-line no-unused-vars
new Vue({
el: '#vue_det',
data: {
author: 'maxzhao',
date: '2019-04-24'
},
methods: {
description: function () {
return this.author + ' - 学的不仅是技术,更是梦想!'
}
}
})

保存之后刷新页面(如果是按照我的安装,则自动添加热加载);

image.png

Html

使用 v-html 指令用于输出 html 代码:

打开 index.html

1
2
3
4
5
6
7
8
<div id="app"></div>
<!-- built files will be auto injected -->
<div id="vue_det">
<h1>author : {{author}}</h1>
<h1>date : {{date}}</h1>
<h1>{{description()}}</h1>
<div v-html="message"></div>
</div>

打开 src/main.js

1
2
3
4
5
6
7
8
new Vue({
el: '#vue_det',
data: {
author: 'maxzhao',
date: '2019-04-24',
message: '<h1>maxzhao_v-html</h1>'
},
//****

自己测试前段界面哦。

属性

HTML 属性中的值应使用 v-bind 指令。

以下实例判断 class1 的值,如果为 true 使用 class1 类的样式,否则不使用该类:

v-bind 指令

打开 index.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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vue_maxzhao</title>
<style>
.class1{
background: #444;
color: #eee;
}
</style>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<div id="vue_det">
<h1>author : {{author}}</h1>
<h1>date : {{date}}</h1>
<h1>{{description()}}</h1>
<div v-html="message"></div>
<label for="r1">修改颜色</label><input type="checkbox" v-model="use" id="r1">
<br><br>
<div v-bind:class="{'class1': use}">
v-bind:class 指令
</div>
</div>
</body>
</html>

打开 src/main.jsdata 中添加,use: false

表达式

Vue.js 都提供了完全的 JavaScript 表达式支持。

打开 index.html

1
2
3
4
5
6
7
8
9
<!--  **   -->      
<div v-bind:class="{'class1': use}">
v-bind:class 指令
</div>
<br>
{{5+5}}<br>
{{ ok ? 'YES' : 'NO' }}<br>
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id">maxzhao</div>

打开 src/main.jsdata 中添加

1
2
3
use: false,
ok: true,
id: 1

指令

指令是带有 v- 前缀的特殊属性。

指令用于在表达式的值改变时,将某些行为应用到 DOM 上。如下例子:

v-if

打开 index.html,接着添加:

1
2
3
4
5
6
7
<br>
<p v-if="seen">现在你看到我了</p>
<template v-if="ok">
<h1>maxzhao</h1>
<p>学的不仅是技术,更是梦想!</p>
<p>哈哈哈,打字辛苦啊!!!</p>
</template>

打开 src/main.jsdata 中添加

1
seen: true

这里, v-if 指令将根据表达式 seen 的值(true 或 false )来决定是否插入 p 元素。

参数

参数在指令后以冒号指明。例如, v-bind 指令被用来响应地更新 HTML 属性:

打开 index.html,接着添加:

1
2
<br>
<pre><a v-bind:href="url">菜鸟教程</a></pre>

打开 src/main.jsdata 中添加

1
url: 'http://localhost:8080'

在这里 href 是参数,告知 v-bind 指令将该元素的 href 属性与表达式 url 的值绑定。

另一个例子是 v-on 指令,它用于监听 DOM 事件:

打开 index.html,接着添加:

1
<pre><a v-on:click="alertMsg">弹出警示</a></pre>

打开 src/main.jsmethods 中添加

1
2
3
4
5
6
7
8
methods: {
description: function () {
return this.author + ' - 学的不仅是技术,更是梦想!'
},
alertMsg: function () {
alert('弹出警示')
}
}

在这里参数是监听的事件名。

修饰符

修饰符是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

1
<form v-on:submit.prevent="onSubmit"></form>


用户输入

在 input 输入框中我们可以使用 v-model 指令来实现双向数据绑定:

双向数据绑定

打开 index.html,接着添加:

1
2
<p>{{ message }}</p>
<input v-model="message">

v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。

按钮的事件我们可以使用 v-on 监听事件,并对用户的输入进行响应。

以下实例在用户点击按钮后对字符串进行反转操作:

字符串反转

打开 index.html,接着添加:

1
2
<p>{{ message }}</p>
<input v-model="message">

main.js中的 methods 中添加

1
2
3
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}

现在大家已经可以知道数据和方法的“存放处”了,接下来就不在详细叙述了,只是走流程。


过滤器

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由”管道符”指示, 格式如下:

1
<h1>{{ message | reverseMessage }}</h1>

过滤器函数接受表达式的值作为第一个参数。

以下实例对输入的字符串第一个字母反转

1
2
3
4
5
6
7
8
9
10
11
12
13
// 与methods同级别添加filters属性
filters: {
reverseMessage: function (value) {
if (!value) return ''
value = value.toString()
return value.split('').reverse().join('')
},
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(11).toUpperCase() + value.slice(1)
}
}

过滤器可以串联:

1
<h1>{{ message |reverseMessage | capitalize }}</h1>

过滤器是 JavaScript 函数,因此可以接受参数:

1
<h1>{{ message |reverseMessage | capitalize | addStr('--maxzhao--') }}</h1>
1
2
3
4
5
addStr: function (value, addStr) {
if (!value) return ''
value = value.toString()
return value + addStr
}

这里,message 是第一个参数,字符串 ‘arg1’ 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。


缩写

v-bind 缩写

Vue.js 为两个最为常用的指令提供了特别的缩写:

1
2
<!-- 完整语法 -->  <a  v-bind:href="url"></a>  
<!-- 缩写 --> <a :href="url"></a></pre>

v-on 缩写

1
2
3
<a  v-on:click="doSomething"></a>  
<!-- 缩写 -->
<a @click="doSomething"></a>

起步结束了,下面开始一些有难度的操作(学过之后简直毫无难度)。

Vue.js 条件与循环

条件判断

v-if 指令

条件判断使用 v-if 指令:

在元素 和 template 中使用 v-if 指令:

1
2
3
4
5
<template v-if="ok">
<h1>maxzhao</h1>
<p>学的不仅是技术,更是梦想!</p>
<p>哈哈哈,打字辛苦啊!!!</p>
</template>

这里, v-if 指令将根据表达式 ok的值(true 或 false )来决定是否插入template元素。

在字符串模板中,如 Handlebars ,我们得像这样写一个条件块:

1
2
3
4
<!-- Handlebars 模板,暂时还不知道有啥用 -->
{{#if ok}}
<h1>Yes</h1>
{{/if}}

v-else 指令

可以用 v-else 指令给 v-if 添加一个 “else” 块:

随机生成一个数字,判断是否大于0.5,然后输出对应信息:

1
2
3
4
5
6
<div v-if="Math.random() > 0.5">
Sorry
</div>
<div v-else>
Not sorry
</div>

v-else-if 指令

v-else-if 在 2.1.0 新增,顾名思义,用作 v-if 的 else-if 块。可以链式的多次使用:

判断 type 变量的值:

1
2
3
4
5
6
7
8
9
10
11
12
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
1
2
3
data: {
type: 'C'
}

v-else 、v-else-if 必须跟在 v-if 或者 v-else-if之后。

v-show 指令

我们也可以使用 v-show 指令来根据条件展示元素:

1
2
<h1 v-show="true">Hello!</h1>
<h1 v-show="false">don't show!</h1>

Vue.js 循环语句

v-for 指令

循环使用 v-for 指令。

v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。

v-for 可以绑定数据到数组来渲染一个列表:

1
2
3
4
5
<ol>
<li v-for="site in sites">
{{ site.name }}
</li>
</ol>
1
2
3
4
5
6
7
data: {
sites: [
{ name: 'Runoob' },
{ name: 'Google' },
{ name: 'Taobao' }
]
}

模板中使用 v-for:

v-for 迭代对象

v-for 可以通过一个对象的属性来迭代数据:

1
2
3
4
5
<ul>
<li v-for="value in object">
{{ value }}
</li>
</ul>
1
2
3
4
5
6
7
8
  data: {
object: {
name: '菜鸟教程',
url: 'http://www.runoob.com',
slogan: '学的不仅是技术,更是梦想!'
}
}
})

第二个的参数为键名:

1
2
3
4
5
6
  <ul>
<li v-for="(value, key) in object">
{{ key }} : {{ value }}
</li>
</ul>
</div>

第三个参数为索引:

1
2
3
4
5
<ul>
<li v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</li>
</ul>

v-for 迭代整数

v-for 也可以循环整数

1
2
3
4
5
<ul>
<li v-for="n in 10">
{{ n }}
</li>
</ul>

v-for指令界面效果

2019-04-25 11-49-53 的屏幕截图.png

Vue.js 计算属性

计算属性关键词: computed。

计算属性在处理一些复杂逻辑时是很有用的。

可以看下以下反转字符串的例子:

1
2
3
4
5
6
<div>
{{ message.split('').reverse().join('') }}
</div>
<div>
{{ reversedMessage }}
</div>
1
2
3
4
5
6
7
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}

实例中声明了一个计算属性 reversedMessage 。

提供的函数将用作属性 vm.reversedMessage 的 getter 。

vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。

computed vs methods

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。

computed setter

computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

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
var vm = new Vue({
el: '#vue_det',
data: {
//****
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
},
site: {
// getter
get: function () {
return this.author + ' ' + this.slogan
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.author = names[0]
this.slogan = names[names.length - 1]
}
}
}
})
// 调用 setter, vm.name 和 vm.url 也会被对应更新
vm.site = 'maxzhao 学的不仅是技术,更是梦想!'
document.write('author: ' + vm.author)
document.write('<br>')
document.write('slogan: ' + vm.slogan)
document.write('<br>')
document.write('site: ' + vm.site)

引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 把代码改了改,应该可以体现 computer 属性“依赖缓存”的概念以及与 method 的差别。如下面代码,cnt 是独立于 vm 对象的变量。在使用 reversedMessage 这个计算属性的时候,第一次会执行代码,得到一个值,以后再使用 reversedMessage 这个计算属性,因为 vm 对象没有发生改变,于是界面渲染就直接用这个值,不再重复执行代码。而 reversedMessage2 没有这个缓存,只要用一次,函数代码就执行一次,于是每次返回值都不一样。

var cnt=1;
var vm = new Vue({
el: '#app',
data: {
message: 'Runoob!'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
cnt+=1;
return cnt+this.message.split('').reverse().join('')
}
},
methods: {
reversedMessage2: function () {
cnt+=1;
return cnt+this.message.split('').reverse().join('')
}
}
})

Vue.js 监听属性

本章节,我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化。

以下实例通过使用 watch 实现计数器:

1
2
3
4
<div>
<p style="font-size:25px;">计数器: {{ counter }}</p>
<button @click="counter++" style="font-size:25px;">点我</button>
</div>
1
2
3
4
5
6
7
8
9
10
var vm = new Vue({
//*******************
data: {
counter: 1
//*******************
});
// F12 打开开发者模式控制台观察效果
vm.$watch('counter', function(nval, oval) {
console.log('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
});

千米和米的换算

1
2
3
4
5
<br>
<div>
千米 : <input type="text" v-model="kilometers">
米 : <input type="text" v-model="meters">
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data: {
//*************
kilometers : 0,
meters:0
},
watch : {
kilometers: function (newVal, oldVal) {
console.log('newVal=' + newVal + ' oldVal=' + oldVal)
this.kilometers = newVal
this.meters = this.kilometers * 1000
},
meters: function (newVal) {
this.kilometers = newVal / 1000
this.meters = newVal
}
}

控制台为什么会打印两次呢?因为kilometers改变执行一次,并且改变了 meters,所以执行的meters改变(又改变了kilometers),所以又打印了一次,但因为 meters在此时并没有改变,所以没有后续触发。

Vue.js 样式绑定

Vue.js class

class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性。

Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。

class 属性绑定

我们可以为 v-bind: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
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vue_maxzhao</title>
<style>
.class1 {
background: #444;
color: #eee;
}
.active {
background: #42b983;
}
.text-danger {
background: red;
}
</style>
</head>
<!-- ***************** -->
<!-- ***************** -->
<div v-bind:class="{ active: isActive }"></div>
<!-- 多个 -->
<div class="active"></div>
<div :class="{ active: isActive , 'text-danger': true }">
BBBBBBBBBBBBB
</div>
<!-- 对象 -->
<div :class="classObj">
AAAAAAAAAAAAAAAAAAAAAAAAAAA
</div>
<!-- 数组 , 等同于 class="active text-danger"-->
<div :class="[activeClass, errorClass]">
AAAAAAAAAAAAAAAAAAAAAAAAAAA
</div>
<!-- 数组中添加表达式-->
<div :class="[activeClass, true?errorClass:'']">C</div>
<div :class="[activeClass, false?errorClass:'']">D</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data: {
//**********************
isActive: true,
activeClass: 'active',
errorClass: 'text-danger'
}
computed: {
//**********************
classObj: function () {
return {
active: true,
'text-danger': true
}
}
}

Vue.js style(内联样式)

这里的所有操作就不写在 js 中了,表达式等都是可以直接写在页面上的。

1
2
3
4
5
6
7
8
9
10
11
<br>
<!-- v-bind 的缩写还记得吧? ":"哦 -->
<div :style="{ color: 'green', fontSize: 30 + 'px' }">
maxzhao_style——普通绑定,'green'、30 为值
</div>
<div :style="{color: 'green',fontSize: '30px'}">
maxzhao_style——对象绑定,{color: 'green',fontSize: '30px'} 是对象
</div>
<div :style="[{color: 'green',fontSize: '30px'},{'font-weight': 'bold'}]">
maxzhao_style——数组对象绑定,[{color: 'green',fontSize: '30px'},{'font-weight': 'bold'}] 是数组对象绑定
</div>

Vue.js 事件处理器

v-on

事件监听可以使用 v-on 指令。

通常情况下,我们需要使用一个方法来调用 JavaScript 方法。

v-on 可以接收一个定义的方法来调用。

1
2
3
4
5
<br>
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button>
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>

js 中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
methods: {
greet: function (event) {
// `this` 在方法里指当前 Vue 实例
console.log('Hello ' + this.author + '!')
// `event` 是原生 DOM 事件
if (event) {
console.log(event.target.tagName)
}
},
say: function (message) {
console.log(message)
}
}
// 还可以在最外层添加 vm.greet()来调用当前方法,直接调用的时候,event并不存在,因为没有点击事件

事件修饰符

Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。

Vue.js通过由点(.)表示的指令后缀来调用修饰符。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<br>
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis">click.stop</a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit">submit.prevent</form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat">click.stop.prevent</a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent>submit.prevent</form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>
<br>

按键修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 需要js methods
methods: {
clear: function (event) {
console.log('------ clear ----------')
if (event) {
console.log(event.target.tagName)
}
},
submit: function (event) {
console.log('------ submit ----------')
if (event) {
console.log(event.target.tagName)
console.log(event.keyCode)//输出当前key code的值
}
},
doSomething: function (event) {
console.log('------ doSomething ----------')
if (event) {
console.log(event.target.tagName)
console.log(event.keyCode)//输出当前ctrlKey 的bool值
}
}
//*****************************

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

1
2
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input @keyup.13="submit" value="keyup = 13 ">

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

1
2
3
4
5
6
7
8
9
<!-- 同上 -->
<input v-on:keyup.enter="submit" value="keyup = 13 ">
<!-- 缩写语法 -->
<input @keyup.enter="submit" value="enter">
<!-- Alt + C -->
<input @keyup.alt.67="clear" value="Alt + C">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Ctrl + Click will Do something</div>
<br>

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

Vue.js 表单

可以用 v-model 指令在表单控件元素上创建双向数据绑定。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  <p>input 元素:</p>
<input v-model="author" placeholder="编辑我……">
<p>author: {{ author }}</p>

<p>textarea 元素:</p>
<p style="white-space: pre">{{ message }}</p>
<textarea v-model="message" placeholder="多行文本输入……">
</textarea>
<br>
<!-- for 后面加 checkbox或radio 的id,点击会选中或取消选中 -->
<p>单个复选框:</p>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
<p>多个复选框:</p>
<input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
<label for="runoob">Runoob</label>
<input type="checkbox" id="google" value="Google" v-model="checkedNames">
<label for="google">Google</label>
<input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
<label for="taobao">taobao</label>
<br>
<span>选择的值为: {{ checkedNames }}</span>
<br>
<div>
<input type="radio" id="cat" value="cat" v-model="picked">
<label for="cat">cat</label>
<br>
<input type="radio" id="dog" value="dog" v-model="picked">
<label for="google">dog</label>
<br>
<span>选中值为: {{ picked }}</span>
</div>
<br>
<select v-model="selected" name="fruit">
<option value="">选择一个网站</option>
<option value="www.baidu.com">baidu</option>
<option value="www.google.com">Google</option>
</select>

<div id="output">
选择的网站是: {{selected}}
</div>
1
2
3
4
checked : false,
checkedNames: [],
picked: 'cat',
selected: ''

修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

1
2
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

1
<input v-model.number="age" type="number">

这通常很有用,因为在 type=”number” 时 HTML 中输入的值也总是会返回字符串类型。

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

1
<input v-model.trim="msg">

Vue.js 组件component

组件(Component)是 Vue.js 最强大的功能之一。

组件可以扩展 HTML 元素,封装可重用的代码。

组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:

img

全局组件

注册一个全局组件语法格式如下:

1
Vue.component(tagName, options)

tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:

1
<tagName></tagName>

实例

1
2
3
4
5
6
7
8
9
10
11
12

<script>
// 注册,要在创建实例之前完成
Vue.component('maxzhao_all', {
template: '<h1>自定义组件 maxzhao_all !</h1>'
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
<maxzhao_all></maxzhao_all>

局部组件

我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:

1
2
3
<div id="vue_det">
<maxzhao></maxzhao>
<maxzhao_all></maxzhao_all>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 注册
Vue.component('maxzhao_all', {
template: '<h1>自定义组件 maxzhao_all ! </h1>'
})
var Child = {
// eslint-disable-next-line no-tabs
template: '<h1>自定义组件 maxzhao !</h1>'
}
// eslint-disable-next-line no-unused-vars
var vm = new Vue({
el: '#vue_det',
components: {
// <maxzhao> 将只在父模板可用
'maxzhao': Child
}

Prop

prop 是父组件用来传递数据的一个自定义属性。

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 “prop”:

1
<maxzhao_all message1="hello!"></maxzhao_all>
1
2
3
4
5
6
// 注册
Vue.component('maxzhao_all', {
// 声明 props
props: ['message1'],
template: '<h1>自定义组件 maxzhao_all params:{{message1}} ! </h1>'
})

首次接触可能会很难理解,其实很简单,就像<div class="class1" ></div> 一样,为当前的divclass 的传递一个 class1的参数。

动态 Prop

1
<maxzhao_all v-bind:message1="author"></maxzhao_all><maxzhao_all :message1="author"></maxzhao_all>
1
2
3
data: {
author: 'maxzhao'
}

Prop 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
// 当前列表中的一条记录
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.name }}</li>'
})
//***************
data: {
sites: [
{ name: 'Runoob' },
{ name: 'Google' },
{ name: 'Taobao' }
]
}
1
2
3
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>

Prop 验证

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
Vue.component('example', {
props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数字,有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})

type 可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件

父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!

我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。

1
2
3
4
5
6
<div id="counter-event-example">
<p>{{ total }}</p>
<!-- 监听自定义的事件-->
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</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
Vue.component('button-counter', {
template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementHandler: function () {
this.counter += 1
this.$emit('increment')
}
}
})
var vm = new Vue({
el: '#vue_det',
data: {
//****************
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}

这个可能需要解释一下(自己的理解),首先加载当前的button按钮,当前按钮的click执行组件的incrementHandler,然后执行当前组件在html中的click事件,为什么要反向执行呢?因为页面中绑定的事件是 当前vue_det下的事件。

如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:

1
<my-component v-on:click.native="doTheThing"></my-component>

data 必须是一个函数

上面例子中,可以看到 button-counter 组件中的 data 不是一个对象,而是一个函数:

1
2
3
4
5
data: function () {
return {
count: 0
}
}

这样的好处就是每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例,如下所示(没有尝试,js基础知识):

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 id="components-demo3" class="demo">
<button-counter2></button-counter2>
<button-counter2></button-counter2>
<button-counter2></button-counter2>
</div>

<script>
var buttonCounter2Data = {
count: 0
}
Vue.component('button-counter2', {
/*
data: function () {
// data 选项是一个函数,组件不相互影响
return {
count: 0
}
},
*/
data: function () {
// data 选项是一个对象,会影响到其他实例
return buttonCounter2Data
},
template: '<button v-on:click="count++">点击了 {{ count }} 次。</button>'
})
new Vue({ el: '#components-demo3' })
</script>

Vue.js 自定义指令

除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。

下面我们注册一个全局指令 v-focus, 该指令的功能是在页面加载时,元素获得焦点:

全局指令:实例 v-focus

1
2
<p>页面载入时,input 元素自动获取焦点:</p>
<input v-focus>
1
2
3
4
5
6
7
8
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})

我们也可以在实例使用 directives 选项来注册局部指令,这样指令只能在这个实例中使用:

局部指令:实例 v-focus

把上面的代码注释掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
var vm = new Vue({
el: '#vue_det',
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})

钩子

钩子函数

指令定义函数提供了几个钩子函数(可选):

  • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  • unbind: 只调用一次, 指令与元素解绑时调用。

钩子函数参数

钩子函数的参数有:

  • el: 指令所绑定的元素,可以用来直接操作 DOM 。
  • binding: 一个对象,包含以下属性:
    • name: 指令名,不包括 v- 前缀。
    • value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2
    • oldValue: 指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression: 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"
    • arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"
    • modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }
  • vnode: Vue 编译生成的虚拟节点。
  • oldVnode: 上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

以下实例演示了这些参数的使用:

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
// 注册一个全局自定义指令 v-focus
Vue.directive('maxzhao', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})

有时候我们不需要其他钩子函数,我们可以简写函数,如下格式:

1
<div v-maxzhao_dir:a.b.c='message' v-maxzhao_color="{ color: 'green', text: 'maxzhao' }" ></div>
1
2
3
4
Vue.directive('maxzhao_color', function (el, binding) {
// 设置指令的背景颜色
el.style.backgroundColor = binding.value.color
})

指令函数可接受所有合法的 JavaScript 表达式,以下实例传入了 JavaScript 对象:

1
2
3
4
5
Vue.directive('maxzhao_color', function (el, binding) {
// 简写方式设置文本及背景颜色
el.innerHTML = binding.value.text
el.style.backgroundColor = binding.value.color
})

Vue.js 路由(终于到了激动人心,阔步前进的时刻)

本章节我们将为大家介绍 Vue.js 路由。

Vue.js 路由允许我们通过不同的 URL 访问不同的内容。

通过 Vue.js 可以实现多视图的单页Web应用(single page web application,SPA)。

Vue.js 路由需要载入 vue-router 库

中文文档地址:vue-router文档

打住:如果是按照本文的安装方式,则默认已经安装了路由


安装

1、直接下载 / CDN

1
wget https://unpkg.com/vue-router/dist/vue-router.js

2、NPM

推荐使用淘宝镜像:

1
cnpm install vue-router

简单实例

Vue.js + vue-router 可以很简单的实现单页应用。

是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。

以下实例中我们将 vue-router 加进来,然后配置组件和路由映射,再告诉 vue-router 在哪里渲染它们。

HTML代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app-router-demo">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>

JavaScript 代码

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
// 0. 如果使用模块化机制编程,导入 Vue 和 VueRouter,要调用 Vue.use(VueRouter)

// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app-router-demo')

// 现在,应用已经启动了!

打眼一看,怎么还是和安装的不一样?这时候的我也是一脸懵逼。先尝试一下这个。最终还是不行,因为new VueRouter这个是直接报错的。采用当前的方式引入:

1
2
3
4
5
6
7
8
9
10
11
12
import VueRouter from 'vue-router'
// demo
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})

接下来我把教程的所有代码都删掉了,直接看脚手架的源码。

直接上手脚手架

为了方便阅读,把router/index.js改为router/indexRouter.js,此时,会有 test/unit/jest.conf.js中的 js 路径修改。

当我想把indexRouter.js移动到components目录下的时候,发现界面报错了。

1
2
3
4
5
6
7
 ERROR  Failed to compile with 2 errors   
These dependencies were not found:

* vue-router/types in ./src/router/indexRouter.js
* vue/types in ./src/router/indexRouter.js

To install them, you can run: npm install --save vue-router/types vue/types

我就按照提示进行了安装

1
2
3
npm install --save vue-router/types vue/types
# 报错 找不到 赶紧
npm i 一下

提示:此处有一个build/webpack.base.conf.js文件下的

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
// ************************
resolve: {
// 在 import 的可以省略文件的后缀名
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
// 此处设置@ 代表src目录,等同于‘/’
'@': resolve('src'),
}
},

提示: /home/maxzhao/code/vue/vue_maxzhao/src/router/index.js文件下

1
2
3
4
5
6
7
8
9
10
// exxport default 只能导出一个对象,直接引入就可以使用
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})

导出多个对象

1
2
3
4
export const str = 'hello world';
export function f(a){ return a+1;}
// 在其它文件中引入
import { str, f } from 'demo1'

实践

src/router/index.js中插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import HelloMaxzhao from '@/components/HelloMaxzhao'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/hello_maxzhao',
name: 'HelloMaxzhao',
component: HelloMaxzhao
}
]
})

新建src/components/HelloMaxzhao.vue

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
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>author:{{author}}</h2>
</div>
</template>

<script>
export default {
name: 'HelloMaxzhao',
data () {
return {
msg: 'Hello MaxZhao',
author: 'maxzhao'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
</style>

浏览器访问:http://localhost:8080/#/hello_maxzhao

点击过的导航链接都会加上样式 **class =”router-link-exact-active router-link-active”**。


接下来我们可以了解下更多关于 的属性。

to

表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<router-link to="/hello_maxzhao" >to /hello_maxzhao</router-link><br>
<!-- 字符串 -->
<router-link to="hello_maxzhao">hello_maxzhao</router-link><br>
<!-- 渲染结果 -->
<a href="#/hello_maxzhao">a href=hello_maxzhao</a><br>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'hello_maxzhao'">v-bind:to hello_maxzhao</router-link><br>
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'hello_maxzhao'">:to hello_maxzhao</router-link><br>
<!-- 同上 -->
<router-link :to="{ path: 'hello_maxzhao' }">:to="{ path: 'hello_maxzhao' }"</router-link><br>
<!-- 命名的路由 -->
<router-link :to="{ name: 'HelloMaxzhao', params: { userId: 123 }}">命名的路由 HelloMaxzhao</router-link><br>
<!-- 带查询参数,下面的结果为 /hello_maxzhao?plan=private -->
<router-link :to="{ path: 'hello_maxzhao', query: { plan: 'private' }}">带查询参数 hello_maxzhao</router-link>

replace

设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。

1
<router-link :to="{ path: '/abc'}" replace></router-link>

append

设置 append 属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

1
<router-link :to="{ path: 'relative/path'}" append></router-link>

tag

有时候想要 <router-link> 渲染成某种标签,例如 <li>。 于是我们使用 tag prop 类指定何种标签,同样它还是会监听点击,触发导航。

1
2
3
<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>

active-class

设置 链接激活时使用的 CSS 类名。可以通过以下代码来替代。

1
2
3
4
5
6
7
8
9
<style>
._active{
background-color : red;
}
</style>
<p>
<router-link v-bind:to = "{ path: '/route1'}" active-class = "_active">Router Link 1</router-link>
<router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

注意这里 class 使用 **active_class=”_active”**。

exact-active-class

配置当链接被精确匹配的时候应该激活的 class。可以通过以下代码来替代。

1
2
3
4
<p>
<router-link v-bind:to = "{ path: '/route1'}" exact-active-class = "_active">Router Link 1</router-link>
<router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

router-link 默认情况下的路由是模糊匹配,例如当前路径是 /article/1 那么也会激活 ,所以当设置 exact-active-class 以后,这个 router-link 只有在当前路由被全包含匹配时才会被激活 exact-active-class 中的 class,例如:

1
<router-link to="/article" active-class="router-active"></router-link>

当用户访问 /article/1 时会被激活为:

1
<a href="#/article" class="router-active" rel="nofollow"></a>

而当使用:

1
<router-link to="/article" exact-active-class="router-active"></router-link>

当用户访问 /article/1 时,不会激活这个 link 的 class:

1
<a href="#/article" rel="nofollow"></a>

event

声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

1
<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>

以上代码设置了 event 为 mouseover ,及在鼠标移动到 Router Link 1 上时导航的 HTML 内容会发生改变。

NPM 路由实例

接下来我们演示了一个使用 npm 简单的路由实例,开始前,请先下载该实例源代码:

路由实例

你也可以在 Github 上下载:https://github.com/chrisvfritz/vue-2.0-simple-routing-example

下载完后,解压该目录,重命名目录为 vue-demo,vu 并进入该目录,执行以下命令:

1
2
3
4
5
# 安装依赖,使用淘宝资源命令 cnpm
cnpm install

# 启动应用,地址为 localhost:8080
cnpm run dev

如果你需要发布到正式环境可以执行以下命令:

1
cnpm run build

执行成功后,访问 http://localhost:8080 即可看到如下界面:

img

beforeEach 跳转路由前

1
2
3
router.beforeEach((to, from, next) => {
// 做一些操作,比如判断当前用户 token 是否过期
});
  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next(‘/‘) 或者 next({ path: ‘/‘ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

afterEach 跳转路由后

1
2
3
router.afterEach(() => {
NProgress.done(); // 结束Progress
});

Vue.js 混入

混入 (mixins)定义了一部分可复用的方法或者计算属性。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

来看一个简单的实例:

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义一个混入对象
var myMixin = {
created: function () {
this.startmixin()
},
methods: {
startmixin: function () {
document.write('欢迎来到混入实例')
}
}
}
var Component1 = Vue.extend({
mixins: [myMixin]
})
new Component1()

选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。

比如,数据对象在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先

以下实例中,Vue 实例与混入对象包含了相同的方法。从输出结果可以看出两个选项合并了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var mixin = {
created: function () {
document.write('混入调用' + '<br>')
}
}
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>',
mixins: [mixin],
//created 参数
created: function () {
document.write('组件调用' + '<br>')
}
})

输出结果为:

1
2
混入调用
组件调用

如果 methods 选项中有相同的函数名,则 Vue 实例优先级会较高。如下实例,Vue 实例与混入对象的 methods 选项都包含了相同的函数:

相同的函数名

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
var mixin = {
methods: {
hellworld: function () {
document.write('HelloWorld 方法' + '<br>');
},
samemethod: function () {
document.write('Mixin:相同方法名' + '<br>');
}
}
}
/* eslint-disable no-new */
var vm = new Vue({
el: '#app',
router,
components: {App},
template: '<App/>',
mixins: [mixin],
methods: {
start: function () {
document.write('start 方法' + '<br>');
},
samemethod: function () {
document.write('Main:相同方法名' + '<br>');
}
}
})
vm.hellworld();
vm.start();
vm.samemethod();

输出结果为:

1
2
3
HelloWorld 方法
start 方法
Main:相同方法名

以上实例,我们调用了以下三个方法:

1
2
3
vm.hellworld();
vm.start();
vm.samemethod();

从输出结果 methods 选项中如果碰到相同的函数名则 Vue 实例有更高的优先级会执行输出。并且全局方法不执行。


全局混入

也可以全局注册混入对象。注意使用! 一旦使用全局混入对象,将会影响到 所有 之后创建的 Vue 实例。使用恰当时,可以为自定义对象注入处理逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
created: function () {
var myOption = this.$options.myOption;
// this.$options 可以获取当前vue对象
if (myOption) {
console.log(this.$options)
document.write(myOption)
}
}
})
/* eslint-disable no-new */
var vm = new Vue({
el: '#app',
router,
components: {App},
template: '<App/>',
myOption: 'hello!'
})

谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。

Vue.js Ajax(vue-resource)

Vue 要实现异步加载需要使用到 vue-resource 库。

1
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>

Get 请求

以下是一个简单的 Get 请求实例,请求地址是一个简单的 txt 文本:

如果需要传递数据,可以使用 this.$http.get(‘get.php’,{params : jsonData}) 格式,第二个参数 jsonData 就是传到后端的数据。

1
2
3
4
5
this.$http.get('get.php',{params : {a:1,b:2}}).then(function(res){
document.write(res.body);
},function(res){
console.log(res.status);
});

post 请求

post 发送数据到后端,需要第三个参数 **{emulateJSON:true}**。

emulateJSON 的作用: 如果Web服务器无法处理编码为 application/json 的请求,你可以启用 emulateJSON 选项。

demo_test_post.php 代码如下:

1
2
3
4
5
6
7
<?php
$name = isset($_POST['name']) ? htmlspecialchars($_POST['name']) : '';
$city = isset($_POST['url']) ? htmlspecialchars($_POST['url']) : '';
echo '网站名: ' . $name;
echo "\n";
echo 'URL 地址: ' .$city;
?>

语法 & API

你可以使用全局对象方式 Vue.http 或者在一个 Vue 实例的内部使用 this.$http来发起 HTTP 请求。

1
2
3
4
5
6
7
// 基于全局Vue对象使用http
Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

// 在一个Vue实例内使用$http
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

vue-resource 提供了 7 种请求 API(REST 风格):

1
2
3
4
5
6
7
get(url, [options])
head(url, [options])
delete(url, [options])
jsonp(url, [options])
post(url, [body], [options])
put(url, [body], [options])
patch(url, [body], [options])

除了 jsonp 以外,另外 6 种的 API 名称是标准的 HTTP 方法。

options 参数说明:

参数 类型 描述
url string 请求的目标URL
body Object, FormData, string 作为请求体发送的数据
headers Object 作为请求头部发送的头部对象
params Object 作为URL参数的参数对象
method string HTTP方法 (例如GET,POST,…)
timeout number 请求超时(单位:毫秒) (0表示永不超时)
before function(request) 在请求发送之前修改请求的回调函数
progress function(event) 用于处理上传进度的回调函数 ProgressEvent
credentials boolean 是否需要出示用于跨站点请求的凭据
emulateHTTP boolean 是否需要通过设置X-HTTP-Method-Override头部并且以传统POST方式发送PUT,PATCH和DELETE请求。
emulateJSON boolean 设置请求体的类型为application/x-www-form-urlencoded

通过如下属性和方法处理一个请求获取到的响应对象:

属性 类型 描述
url string 响应的 URL 源
body Object, Blob, string 响应体数据
headers Header 请求头部对象
ok boolean 当 HTTP 响应码为 200 到 299 之间的数值时该值为 true
status number HTTP 响应码
statusText string HTTP 响应状态
方法 类型 描述
text() 约定值 以字符串方式返回响应体
json() 约定值 以格式化后的 json 对象方式返回响应体
blob() 约定值 以二进制 Blob 对象方式返回响应体

axios(听说比vueresource更好)

基于promise用于浏览器和node.js的http客户端

特点

  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和响应
  • 能转换请求和响应数据
  • 能取消请求
  • 自动转换JSON数据
  • 浏览器端支持防止CSRF(跨站请求伪造)

安装

npm安装

1
$ npm install axios

bower安装

1
$ bower install axios

通过cdn引入

1
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

例子

发起一个GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Make a request for a user with a given ID
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

// Optionally the request above could also be done as
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

发起一个POST请求

1
2
3
4
5
6
7
8
9
10
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

同时发起多个请求

1
2
3
4
5
6
7
8
9
10
11
12
function getUserAccount() {
return axios.get('/user/12345');
}

function getUserPermissions() {
return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// Both requests are now complete
}));

官方地址:http://www.axios-js.com/zh-cn/docs/

其它插件

NProgress 进度条

1
2
3
4
NProgress.start() // —start 
NProgress.set(0.4)// — 将进度设置到具体的百分比位置
NProgress.inc() // — 少量增加进度
NProgress.done()// — 将进度条标为完成状态

vuedraggable 拖动

vue-count-to 数字滚动

showdown 使页面支持 markdown

Mock.mock() 拦截请求响应数据

参考

问题

Failed to mount component: template or render function not defined.

1
2
3
4
5
6
7
[Vue warn]: Failed to mount component: template or render function not defined.

found in

---> <Anonymous>
<App> at src/App.vue
<Root>

因为 vue 版本高了,需要在 require 之后 加上 default, 来指定文件中的 export default

1
2
Try adding .default to the end of your require().
component: require('./index/index.vue').default

You cannot set a form field before rendering a field associated with the value

只能少传参,不能多传、错传参数。

1
2
3
let thisDetail = pick(that.detail, 'money',
'goodsName', 'remark', 'delStatus', 'expenseTime');
that.form.setFieldsValue(thisDetail);

本文地址: https://github.com/maxzhao-it/blog/post/5a8f92e/