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> <div>{{msg+123}}</div> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ 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"> <div v-cloak>{{msg}}</div> <div v-cloak>{{msg+123}}</div> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ 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"> <div v-cloak>{{msg}}</div> <div v-text='msg'></div> <div v-html='msg1'></div>
</div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { msg: 'hello world!', msg1: '<h1>hello world!</h1>' } }); </script>
|
v-pre
显示原始信息,跳过编译过程(分析编译过程)
数据响应式
如何理解响应式:
什么是数据绑定:
v-once 只编译一次:
- 显示内容之后不再具有响应式功能(不会随数据改变而再改变)
双向绑定
1 2 3 4 5
| <div id="app"> <div v-cloak>{{msg}}</div> <input type="text" v-model="msg"> </div>
|
MVVM设计思想
- M(model) (数据对象等)
- V(view) (页面显示)
- VM(View Model) (处理M、V之间的关系)

事件绑定
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 @click='num++'>点击</button> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ 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> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { num: 0 }, methods: { add: function() { this.num++; } } }); </script>
|
1 2
| <button v-on:click='say("hi",$event)'>Say hi</button>
|
1
| <a v-on:click.stop="handle"> 跳转 </a>
|
1
| <a v-on:click.prevent="handle"> 跳转 </a>
|
1 2 3 4
| <input v-on:keyup.enter='submit'>
<input v-on:keyup.delete='handle'>
|
属性绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> <a :href="url">百度</a> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { url: 'http://www.baidu.com' } }); </script>
|
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> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ 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> .active { width: 100px; height: 100px; } .error { background-color: orange; } </style> </head> <body> <div id="app"> <div v-bind:class='[ActiveClass,ErrorClass]'></div> </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' } }); </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> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { ActiveClass: 'active', ErrorClass: 'error', isTest: true } }); </script> </body>
|
style绑定
1 2
| <div v-bind:style="{ color: activeColor, fontSize: fontSize }"></div>
|
1
| <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
| <div id="app"> <div v-if='score>=90'>优秀</div> <div v-else-if='score>=80&&score<90'>良好</div> <div v-else='score<80'>一般</div> <div v-show='flag'>123</div> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { score: 95, flag: false } }); </script>
|
1 2 3 4
| <li v-for='item in list'>{{item}}</li>
<li v-for='(item,index) in list'>{{item}} + '------' +{{index}}</li>
|
- key 的作用:帮助 Vue 区分不同的元素,从而提高性能
1 2
| <li :key='item.id' v-for='(item,index) in list'>{{item}} + ' '------' {{index}}</li>
|
1
| <div v-for='(value, key, index) in object'></div>
|
1
| <div v-if='value==12' v for='(value, key, index) in object'></div>
|
Vue常用特性
表单基本操作
获取单选框中的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<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: { 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
|
<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: { hobby: ['2', '3'], }, }) </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
| <div> <span>职业:</span>
<select v-model='occupation' multiple> <option value="0">请选择职业...</option> <option value="1">教师</option> <option value="2">软件工程师</option> <option value="3">律师</option> </select> <textarea v-model='desc'></textarea> </div> <script> new Vue({ data: { occupation: ['2', '3'], desc: 'nihao' }, }) </script>
|
表单修饰符
自定义指令
Vue.directive 注册全局指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
<input type="text" v-focus> <script>
Vue.directive('focus', { 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">
Vue.directive('color', { bind: function(el, binding){ 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: { 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">
<div>{{reverseString}}</div> <div>{{reverseString}}</div> <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: { reverseString: function(){ console.log('computed') var total = 0; for(var i=0;i<=this.num;i++){ total += i; } return total; } } }); </script>
|
侦听器
过滤器
1 2 3 4 5 6
| <div>{{msg | upper}}</div>
<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> 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> <menu-item title='来自父组件的值'></menu-item>
<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', { 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>
<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">
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() { hub.$emit('jerry-event', 2); } }, mounted: function() { 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() { hub.$emit('tom-event', 1); } }, mounted: function() { hub.$on('jerry-event', (val) => { this.num += val; }); } }); var vm = new Vue({ el: '#app', data: {
}, methods: { handle: function() { 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"> <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>默认内容</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>
<p slot='header'>标题信息</p> <p>主要内容1</p> <p>主要内容2</p> <p slot='footer'>底部信息信息</p> </base-layout>
<base-layout> <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">
<fruit-list :list='list'>
<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){
}); p.then(function(ret){
},function(ret){
});
|
基于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">
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">
function foo() { return new Promise(function(resolve, reject){ setTimeout(function(){ reject('error'); }, 100); }) }
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中有一个实例的状态发生改变(变为fulfilled或rejected),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
| <script type="text/javascript">
function queryData(url) { return new Promise(function(resolve, reject){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState != 4) return; if(xhr.readyState == 4 && xhr.status == 200) { resolve(xhr.responseText); }else{ reject('服务器错误'); } }; xhr.open('get', url); xhr.send(null); }); }
var p1 = queryData('http://localhost:3000/a1'); var p2 = queryData('http://localhost:3000/a2'); var p3 = queryData('http://localhost:3000/a3'); Promise.all([p1,p2,p3]).then(function(result){ console.log(result) }) Promise.race([p1,p2,p3]).then(function(result){ console.log(result) }) </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('http://localhost:3000/fdata').then(function(data){ return data.text(); }).then(function(data){ 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对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如
JSON,BLOB或者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 属性里面 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 10
| # 配置公共的请求头 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定义的函数中使用- async/await 让异步代码看起来、表现起来更像同步代码
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
| # 1. async 基础用法 # 1.1 async作为一个关键字放到函数前面 async function queryData() { # 1.2 await关键字只能在使用async定义的函数中使用 await后面可以直接跟一个 Promise实例对象 var ret = await new Promise(function(resolve, reject){ setTimeout(function(){ resolve('nihao') },1000); }) return ret; } # 1.3 任何一个async函数都会隐式返回一个promise 我们可以使用then 进行链式编程 queryData().then(function(data){ console.log(data) })
#2. async 函数处理多个异步函数 axios.defaults.baseURL = 'http://localhost:3000';
async function queryData() { # 2.1 添加await之后 当前的await 返回结果之后才会执行后面的代码 var info = await axios.get('async1'); #2.2 让异步代码看起来、表现起来更像同步代码 var ret = await axios.get('async2?info=' + info.data); return ret.data; }
queryData().then(function(data){ console.log(data) })
|
Vue前端路由
路由的概念
路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。
那么url地址和真实的资源之间就有一种对应的关系,就是路由。
- 后端路由是由服务器端进行实现,并完成资源的分发
- 前端路由是依靠hash值(锚链接)的变化进行实现
- 前端路由的基本概念:根据不同的事件来显示不同的页面内容,即事件与事件处理函数之间的对应关系
前端路由的初体验
前端路由是基于hash值的变化进行实现的(比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换)核心实现依靠一个事件,即监听hash值变化的事件
1 2 3 4
| window.onhashchange = function(){ 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
| <div id="app"> <a href="#/zhuye">主页</a> <a href="#/keji">科技</a> <a href="#/caijing">财经</a> <a href="#/yule">娱乐</a>
<component :is="comName"></component> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> const zhuye = { template: '<h1>主页信息</h1>' }
const keji = { template: '<h1>科技信息</h1>' }
const caijing = { template: '<h1>财经信息</h1>' }
const yule = { template: '<h1>娱乐信息</h1>' }
const vm = new Vue({ el: '#app', data: { comName: 'zhuye' }, components: { zhuye, keji, caijing, yule } })
window.onhashchange = function() { 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.
基本使用
路由重定向
在路由规则中添加一条路由规则即可,如下:
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> <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> </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> <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 = { template: '<h1>User组件---id为{{$route.params.id}}</h1>' }; const Register = { template: '<h1>Register组件</h1>' }; const router = new VueRouter({ routes: [{ 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来接收参数。
1 2 3 4 5 6 7 8 9 10 11 12
| var User = { props:["id"], template:"<div>用户:{{id}}</div>" }
var myRouter = new VueRouter({ routes: [ { path: "/user/:id", component: User,props:true }] });
|
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: [ { path: "/user/:id", component: User,props:{username:"jack",pwd:123} } ] });
|
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: [ { 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: [ { 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 );