组件
1 fetch和axios
axios与fetch实现数据请求
(1)fetch(不是所有浏览器都支持,谷歌浏览器支持)
XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好。 兼容性不好
polyfill: https://github.com/camsong/fetch-ie8
1.1 fetche使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>fetch</title> <script src="js/vue.js"></script> </head> <body> <div id="box">
<button @click="handleClick()">获取影片信息</button> <ul> <li v-for="data in datalist"> <h3>{{data.name}}</h3> <img :src="data.poster"/> </li> </ul> </div> <script type="text/javascript"> new Vue({ el: "#box", data: { datalist: [] }, methods: { handleClick() {
</script> </body> </html>
|
1.2 axios的使用
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
|
<!DOCTYPE html> <html> <head> <metacharset="utf-8"> <title>axios</title> <scripttype="text/javascript"src="js/vue.js"></script> <scriptsrc="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <divid="box"> <button @click="handleClick()">正在热映</button>
<ul> <liv-for="data in datalist"> <h3>{{data.name}}</h3> <img:src="data.poster"/> </li> </ul> </div> <scripttype="text/javascript">
new Vue({ el:"#box", data:{ datalist:[] }, methods:{ handleClick(){ axios.get("./json/test.json").then(res=>{ console.log(res.data.data.films)
</script> </body> </html>
|
2 计算属性
1 2 3 4 5
|
复杂逻辑,模板难以维护 (1) 基础例子 (2) 计算缓存 VS methods-计算属性是基于它们的依赖进行缓存的。-计算属性只有在它的相关依赖发生改变时才会重新求值 (3) 计算属性 VS watch - v-model3
|
2.1 通过计算属性实现名字首字母大写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> {{mytext.substring(0,1).toUpperCase()+mytext.substring(1)}} <p>计算属性:{{getname}}</p> <p>普通方法:{{getNameMethod()}}</p> </div> </body> <script> var vm = new Vue({ el: '#box', data: { mytext:'lqz', }, computed:{ getname(){
</script> </html>
|
2.2 通过计算属性重写过滤案例
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <p><inputtype="text"v-model="mytext" @input="handleChange"></p> <ul> <liv-for="data in newlist">{{data}}</li> </ul> </div> </body> <script> var vm = new Vue({ el: '#box', data: { mytext: '', datalist: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac'],
}, computed: { newlist() { var newlist = this.datalist.filter(item => { return item.indexOf(this.mytext) > -1 }) return newlist }, },
}) </script> </html>
|
3 Mixins
1
|
混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
|
4 虚拟dom与diff算法 key的作用
4.1 Vue2.0 v-for 中 :key 有什么用呢?
1 2 3 4 5 6 7 8
|
其实呢不只是vue,react中在执行列表渲染时也会要求给每个组件添加key这个属性。 key简单点来说就是唯一标识,就像ID一样唯一性 要知道,vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法。
只做同层级的对比 按照key值比较,出现新的key就插入 通组件对比
|
4.2 虚拟DOM的diff算法
4.3 具体实现
4.3.1 把树按照层级分解
4.3.2 同key值比较
4.3.3 通组件对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<divid="box"> <divv-if="isShow">111</div> <pv-else>222</p>
<divv-if="isShow">111</div> <divv-else>222</div>
</div>
|
https://segmentfault.com/a/1190000020170310
5 组件化开发基础
5.1 组件是什么?有什么用
1 2 3
|
扩展 HTML 元素,封装可重用的代码,目的是复用 -例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html -组件把js,css,html放到一起,有逻辑,有样式,有html
|
6 组件注册方式
1 2 3
|
1 全局组件 Vue.component 2 局部组件
|
6.1 定义全局组件,绑定事件,编写样式
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <navbar></navbar> </div> </body> <script>
Vue.component('navbar',{ template:` <div> <button @click="handleClick">返回</button> 我是NavBar <buttonstyle="background: red">主页</button> </div> `, methods:{ handleClick(){ console.log('nav nav') } } }) var vm = new Vue({ el: '#box', data: { },
}) </script> </html>
|
6.2 定义局部组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
Vue.component('navbar', { template: ` <div> <button @click="handleClick">返回</button> 我是NavBar <buttonstyle="background: red">主页</button> <br> <child></child> </div> `, methods: { handleClick() { console.log('nav nav') }, }, components: { child: { template: `<button>儿子</button>`, }
} })
|
7 组件编写方式与Vue实例的区别
1 2 3
|
1 自定义组件需要有一个root element,一般包裹在一个div中 2 父子组件的data是无法共享 3 组件可以有data,methods,computed....,但是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 25 26 27
|
Vue.component('navbar', { template: ` <div> <button @click="handleClick">返回</button> 我是NavBar{{aa}} <buttonstyle="background: red">主页</button> <br> <child></child> </div> `, methods: { handleClick() { console.log('nav nav') }, }, components: { child: { template: `<button>儿子</button>`, }
}, data(){ return { aa:'lqz' } }, })
|
8 组件通信
1 2 3 4 5
|
1 父子组件传值 (props down, events up) 2 父传子之属性验证props:{name:Number}Number,String,Boolean,Array,Object,Function,null(不限制类型) 3 事件机制a.使用 $on(eventName) 监听事件b.使用 $emit(eventName) 触发事件 4 Ref<input ref="mytext"/> this.$refs.mytext 5 事件总线var bus = new Vue();* mounted生命周期中进行监听
|
8.1 父子通信之父传子
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <navbarmyname="lqz"></navbar> <navbarmyname="egon"></navbar> <navbar:myname="egon"></navbar> <navbar:myname="egon"isshow="false"></navbar> <navbar:myname="egon":isshow="false"></navbar> </div> </body> <script>
Vue.component('navbar', { template: ` <div> <button>返回</button> 父组件传递的内容是:{{myname}} <button>主页</button> <br> </div> `, props:['myname'] }) var vm = new Vue({ el: '#box', data: {},
}) </script> </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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <navbarmyname="egon":isshow="false"></navbar> <navbarmyname="egon"isshow="false"></navbar> </div> </body> <script> Vue.component('navbar', { template: ` <div> <button>返回</button> 父组件传递的内容是:{{myname}} 传入的布尔是{{isshow}} <button>主页</button> <br> </div> `,
props:{ myname:String, isshow:Boolean, }, }) var vm = new Vue({ el: '#box', data: {},
}) </script> </html>
|
8.2 父子通信之子传父(通过事件)
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> 子组件中监听自定义事件,随便起名
<navbar @myevent="handleClick($event)"></navbar> </div> </body> <script> Vue.component('navbar', { template: ` <div> <button>返回</button> 组件 <button @click="handleEvent">点击按钮把子组件数据传递到父组件</button> <br> </div> `, data(){ return { name:'lqz' } }, methods:{ handleEvent(){
this.$emit('myevent',100) } } }) var vm = new Vue({ el: '#box', data: {}, methods:{ handleClick(ev){ console.log('点击子组件,我会执行') console.log(ev)
} }
}) </script> </html>
|
8.3 通过子传父控制字组件显示隐藏
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> 普通方式 <button @click="isShow=!isShow">点击隐藏显示</button> <navbarv-show="isShow"></navbar>
<hr> 字传父方式 <mybutton @myevent="handleShow"></mybutton> <navbarv-show="isShow"></navbar> </div> </body> <script> Vue.component('mybutton', { template: ` <div> <button @click="handleClick">点我隐藏显示</button> </div> `, methods: { handleClick() { this.$emit('myevent') } } })
Vue.component('navbar', { template: ` <div> <ul> <li>111</li> <li>222</li> <li>333</li> </ul> </div> `, data() { return { name: 'lqz' } }, methods: { handleEvent() {
this.$emit('myevent', 100) } } }) var vm = new Vue({ el: '#box', data: { isShow: true }, methods: { handleShow() { this.isShow=!this.isShow
} }
}) </script> </html>
|
8.4 ref属性
1 2 3 4
|
ref放在标签上,拿到的是原生节点 ref放在组件上,拿到的是组件对象, 通过这种方式实现子传父(this.$refs.mychild.text) 通过这种方式实现父传子(调用子组件方法传参数)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box">
<inputtype="text"ref="mytext"> <button @click="handleClick">点我</button> <childref="mychild"></child> </div> </body> <script> Vue.component('child',{ template:`<div>child</div>`, data(){ return { text:'子组件数据' } }, methods:{ add(){ console.log('子组件的add方法') } } }) var vm = new Vue({ el: '#box', data: {
}, methods: { handleClick() { console.log(this)
</script> </html>
|
8.5 事件总线(不同层级的不通组件通信)
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <child1></child1> <child2></child2> </div> </body> <script> var bus=new Vue() Vue.component('child1', { template: `<div> <inputtype="text"ref="mytext"> <button @click="handleClick">点我</button> </div>`, methods:{ handleClick(){ bus.$emit('suibian',this.$refs.mytext.value) } } }) Vue.component('child2', { template: `<div> <div>收到的消息 {{msg}}</div> </div>`, data(){ return {msg:''} }, mounted(){
console.log('当前组件dom创建完后悔执行')
bus.$on('suibian',(item)=>{ console.log('收到了',item) this.msg=item }) } }) var vm = new Vue({ el: '#box', data: {}, methods: { handleClick() { console.log(this)
console.log(this.$refs.mytext.value) console.log(this.$refs.mychild.text)
this.$refs.mychild.add('传递参数')
} }
}) </script> </html>
|
9 动态组件
1 2
|
1 <component> 元素,动态地绑定多个组件到它的 is 属性 2 <keep-alive> 保留状态,避免重新渲染
|
9.1 基本使用
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
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <ul> <li><a @click="who='child1'">首页</a></li> <li><a @click="who='child2'">商品</a></li> <li><a @click="who='child3'">购物车</a></li> </ul> <component:is="who"></component> </div> </body> <script> var bus = new Vue() Vue.component('child1', { template: `<div> 首页 </div>`,
}) Vue.component('child2', { template: `<div> 商品 </div>`, }) Vue.component('child3', { template: `<div> 购物车 </div>`, }) var vm = new Vue({ el: '#box', data: { who:'child1' },
}) </script> </html>
|
9.2 keep-alive使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
<!DOCTYPE html> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Title</title> <scriptsrc="js/vue.js"></script> </head> <body> <divid="box"> <ul> <li><a @click="who='child1'">首页</a></li> <li><a @click="who='child2'">商品</a></li> <li><a @click="who='child3'">购物车</a></li> </ul> <keep-alive> <component:is="who"></component> </keep-alive>
</div> </body> <script> var bus = new Vue() Vue.component('child1', { template: `<div> 首页 </div>`,
}) Vue.component('child2', { template: `<div> 商品 <inputtype="text"> </div>`, }) Vue.component('child3', { template: `<div> 购物车 </div>`, }) var vm = new Vue({ el: '#box', data: { who:'child1' },
}) </script> </html>
|
每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)