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
显示原始信息,跳过编译过程(分析编译过程)
数据响应式
如何理解响应式:
什么是数据绑定:
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之间的关系)
事件绑定
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是固定名称,传递该事件到参数 -->
|
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'> <!-- 按esc键触发 --> <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 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>
|
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>
|
分支循环结构
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>
|
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>
|
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
| <!-- 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>
|
获取下拉框和文本框中的值
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>
|
表单修饰符
自定义指令
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
| <!-- 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">
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"> <!-- 这里的所有组件标签中嵌套的内容会替换掉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>默认内容</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"> <!-- 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){
}); 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"> /* 基于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中有一个实例的状态发生改变(变为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 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对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如
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
| # 配置公共的请求头 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
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
| <!-- 被 vue 实例控制的 div 区域 --> <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> <!-- 被 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 = { 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 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 = { 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>
|
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 );