Vue组件
fetch和axios
axios与fetch实现数据请求
fetch(不是所有浏览器都支持,谷歌浏览器支持),XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好。 兼容性不好
polyfill: https://github.com/camsong/fetch-ie8
1、fetche使用
<!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() { //https://m.maizuo.com/v5/?co=mzmovie#/films/nowPlaying fetch("./json/test.json").then(res => res.json()).then(res => { console.log(res.data.films) this.datalist = res.data.films }) } } }) /* // post-1 fetch("**",{ method:'post', headers: { "Content‐Type": "application/x‐www‐form‐urlencoded" }, body: "name=kerwin&age=100", credentials:"include" }).then(res=>res.json()).then(res=>{console.log(res)}); // post-2 fetch("**",{ method:'post', headers: { "Content‐Type": "application/json" }, body: JSON.stringify({ myname:"kerwin", myage:100 }) }).then(res=>res.json()).then(res=>{console.log(res)}); */ </script> </body> </html>
2、axios的使用
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>axios</title> <script type="text/javascript" src="js/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.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(){ axios.get("./json/test.json").then(res=>{ console.log(res.data.data.films) // axios 自动包装data属性 res.data this.datalist = res.data.data.films }).catch(err=>{ console.log(err); }) } } }) </script> </body> </html>
Mixins
混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
虚拟dom与diff算法 key的作用
1、Vue2.0 v-for 中 :key 有什么用呢?
其实呢不只是vue,react中在执行列表渲染时也会要求给每个组件添加key这个属性。
key简单点来说就是唯一标识,就像ID一样唯一性
要知道,vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法。
只做同层级的对比
按照key值比较,出现新的key就插入
通组件对比
2、虚拟DOM的diff算法
具体实现
把树按照层级分解
同key值比较
通组件对比
<div id="box"> <div v-if="isShow">111</div> <p v-else>222</p> <!-- {tag:div,value:111} {tag:p,value:222} 直接不比较,直接删除div,新增p --> <div v-if="isShow">111</div> <div v-else>222</div> <!-- {tag:div,value:111} {tag:div,value:222} 比较都是div,只替换文本内容 --> </div>
https://segmentfault.com/a/1190000020170310
组件开发基础
什么是组件以及组件的作用
扩展 HTML 元素,封装可重用的代码,目的是复用
-例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html
-组件把js,css,html放到一起,有逻辑,有样式,有html
组件注册方式
1 全局组件
Vue.component
2 局部组件
定义全局组件,绑定事件,编写样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> <navbar></navbar> </div> </body> <script> //没有代码提示,语法检查,目前这么用 //后面会使用webpack打包,直接定义成 xx.vue文件,通过webpack打包 Vue.component('navbar',{ template:` <div> <button @click="handleClick">返回</button> 我是NavBar <button style="background: red">主页</button> </div> `, methods:{ handleClick(){ console.log('nav nav') } } }) var vm = new Vue({ el: '#box', data: { }, }) </script> </html>
定义局部组件
Vue.component('navbar', { template: ` <div> <button @click="handleClick">返回</button> 我是NavBar <button style="background: red">主页</button> <br> <child></child> </div> `, methods: { handleClick() { console.log('nav nav') }, }, components: { child: { template: `<button>儿子</button>`, } } })
组件编写方式与Vue实例的区别
1、自定义组件需要有一个root element,一般包裹在一个div中
2、父子组件的data是无法共享
3、组件可以有data,methods,computed....,但是data 必须是一个函数
Vue.component('navbar', { template: ` <div> <button @click="handleClick">返回</button> 我是NavBar{{aa}} <button style="background: red">主页</button> <br> <child></child> </div> `, methods: { handleClick() { console.log('nav nav') }, }, components: { child: { template: `<button>儿子</button>`, } }, data(){ return { aa:'lqz' } }, })
组件通信
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生命周期中进行监听
1、父子通信之父传子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> <!--保证属性名和props中的属性名和变量名一致即可--> <navbar myname="lqz"></navbar> <navbar myname="egon"></navbar> <!--注意数据绑定--> <navbar :myname="egon"></navbar> <!--可以传多个,但是注意,传入的isshow是字符串,可以使用数据绑定变成布尔--> <navbar :myname="egon" isshow="false"></navbar> <navbar :myname="egon" :isshow="false"></navbar> </div> </body> <script> //没有代码提示,语法检查,目前这么用 //后面会使用webpack打包,直接定义成 xx.vue文件,通过webpack打包 Vue.component('navbar', { template: ` <div> <button>返回</button> 父组件传递的内容是:{{myname}} <button>主页</button> <br> </div> `, props:['myname'] }) var vm = new Vue({ el: '#box', data: {}, }) </script> </html>
属性验证
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> <navbar myname="egon" :isshow="false"></navbar> <!--报错--> <navbar myname="egon" isshow="false"></navbar> </div> </body> <script> Vue.component('navbar', { template: ` <div> <button>返回</button> 父组件传递的内容是:{{myname}} 传入的布尔是{{isshow}} <button>主页</button> <br> </div> `, // props:['myname'], props:{ myname:String, isshow:Boolean, }, }) var vm = new Vue({ el: '#box', data: {}, }) </script> </html>
2、父子通信之子传父(通过事件)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> 子组件中监听自定义事件,随便起名 <!-- <navbar @myevent="handleClick"></navbar>--> <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') //myevent:子组件中监听自定义事件 this.$emit('myevent',100) //100表示传递的参数 } } }) var vm = new Vue({ el: '#box', data: {}, methods:{ handleClick(ev){ console.log('点击子组件,我会执行') console.log(ev) } } }) </script> </html>
3、通过子传父控制字组件显示隐藏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> 普通方式 <button @click="isShow=!isShow">点击隐藏显示</button> <navbar v-show="isShow"></navbar> <hr> 字传父方式 <mybutton @myevent="handleShow"></mybutton> <navbar v-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') //myevent:子组件中监听自定义事件 this.$emit('myevent', 100) //100表示传递的参数 } } }) var vm = new Vue({ el: '#box', data: { isShow: true }, methods: { handleShow() { this.isShow=!this.isShow } } }) </script> </html>
4、ref属性
ref放在标签上,拿到的是原生节点
ref放在组件上,拿到的是组件对象,
通过这种方式实现子传父(this.$refs.mychild.text)
通过这种方式实现父传子(调用子组件方法传参数)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> <!-- 通过ref,获取input的值--> <input type="text" ref="mytext"> <button @click="handleClick">点我</button> <child ref="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) //this.$refs.mytext 获取到input控件,取出value值 console.log(this.$refs.mytext.value) console.log(this.$refs.mychild.text) // this.$refs.mychild.add() this.$refs.mychild.add('传递参数') } } }) </script> </html>
5、事件总线(不同层级的不同组件通信)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="box"> <child1></child1> <child2></child2> </div> </body> <script> var bus=new Vue() //new一个vue的实例,就是中央事件总线 Vue.component('child1', { template: `<div> <input type="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(){ //生命周期,当前组件dom创建完后悔执行 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) //this.$refs.mytext 获取到input控件,取出value值 console.log(this.$refs.mytext.value) console.log(this.$refs.mychild.text) // this.$refs.mychild.add() this.$refs.mychild.add('传递参数') } } }) </script> </html>
动态组件
<component> 元素,动态地绑定多个组件到它的 is 属性 2 <keep-alive> 保留状态,避免重新渲染
1、基本使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="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() //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>
2、keep-alive使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="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() //new一个vue的实例,就是中央事件总线 Vue.component('child1', { template: `<div> 首页 </div>`, }) Vue.component('child2', { template: `<div> 商品 <input type="text"> </div>`, }) Vue.component('child3', { template: `<div> 购物车 </div>`, }) var vm = new Vue({ el: '#box', data: { who:'child1' }, }) </script> </html>