-
组件
-
Vue有两大核心内容
- 指令
- 组件
-
什么是组件化?【 为什么要用组件 】
- 为了避免多人开发造成的冲突
- 为了加快开发效率
- 为了便利更新和维护
- 组件化: 就是使用具有独立功能的一个整体【 组件 】来进行项目开发的一个趋势 【 流行 】
-
什么是组件?
- 组件是一个html css js img 等的一个聚合体
- 在Vue中使用了一个叫做单文件组件的技术来实现组件
- 它是一个 xxx.vue 文件
- 这个文件在浏览器中不能运行,必须经过编译【 gulp webpack 】才能运行
-
Vue里面是如何实现组件的?
-
扩展: Vue.extend() 它就是对Vue功能的扩展,这个扩展就是组件
<script> /* 1. 通过实例化Vue构造器函数得到一个Vue实例,这个实例我们称之 为'根实例',它是最大的父级 2. 这个根实例是以标签的形式存在的,我们也称之为' 根组件 ' 3. 根实例也是一个组件,但是我们得到只是根组件 4. Vue.extend() 它就是对Vue功能的扩展,这个扩展就是组件 5. Vue.extend如何使用? - 通过new Vue.extend() 发现和其和new Vue是一样的 - 组件就是一个以标签化呈现的东西,所以我应该像标签一样使用 - 但是无论是 html3 还是 html5 肯定不会同意它随意来个标签的 - Vue会将组件编译成html结构 - Vue的这个处理过程,我们称之为 ' 组件注册 ' 总结: 1. Vue是通过Vue.extend() 来实现组件的 2. Vue的组件的使用时需要注册的 */ //下面两个基本一样 //所以不用new Vue来扩展组件,直接vue.extend() console.log( Vue ) /* ƒ Vue (options) { if (!(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options);} */ console.log( Vue.extend()) /* ƒ VueComponent (options) { this._init(options); } */ new Vue({ el: '#app' }) </script>
-
-
Vue中是如何使用组件的?
-
组件注册
-
全局注册:在当前页的所有根实例里面都可以引用
//1、用vue.extend() const Hellooo = vue.extend({ template:'<div>这是全局组件</div>' }) //vue.component('组件名',组件配置项) vue.component('Hello',Hellooo)//这里是注册部分 //然后再到vue的根实例#app中使用组件<Hello></Hello>即可 new Vue({ el: '#app' }) //2、全局注册的简写方式 vue.component('Hello',{ template:'<div>这是全局组件</div>' }) //3、上面这两种,在写的过程种都没有代码提示,为了有,一般 将template拿出来,在el在body中的位置下面,写一个<template> 标签,就类似于new Vue中的el,不要写在了#app根实例里面,不然, 还不待放到组件中就直接解析 <body> <div id="app"> </div> <template id="hahaha"> <div>这里是全局组件</div> </template> </body> vue.component('Hello',{ template:'#hahaha' })
-
局部注册:在当前根实例里面才能有用
//局部注册,写在VM里面 new Vue({//VM el: '#app', components: { //局部注册组件的选项,注意这里是带有"s"的 // 组件名: 组件选项 'Hello': { template: '<div> Hello 这里是局部注册 </div>' } } })
-
-
组件的起名
- 大驼峰 HeadTitle 使用时
<head-title></head-title>
- 小写横杠 head-title 使用时
<head-title></head-title>
- 一个单词 Hello 使用时
<hello></hello>
或者<Hello></Hello>
【 推荐这种,大写可以和原生标签区分 】 - 不要用和原生标签一样的名称
- 大驼峰 HeadTitle 使用时
-
-
-
组件通信 【 使用组件实现todolist 】
-
组件的使用规则?
- 具有直接父子级关系的标签,会出现渲染问题,我们通过is属性来解决
- 如:ul>li、ol>li、dl>dt|dd、select>option、table>tr>td
<body> <div id="app"> <table border="1"> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr is = "Hello"></tr> <!--这里不是直接写<Hello></Hello>,不然会出问题,用is属性--> </table> </div> </body> <script src="vue.js"></script> <script> /* 业务: 给上面的表格增加一个行,这一行用一个组件表示 通过以上案例发现: 组件在父子级是有直接关系的标签中是不能直接解析的, 会出问题 */ Vue.component('Hello',{ template: ` <tr> <td>4</td> <td>5</td> <td>6</td> </tr> ` }) new Vue({ el: '#app' }) </script>
-
动态组件
-
动态组件指的是通过 Vue 提供的 component组件 + is 属性来
实现(vue中component组件是内置的,不需要注册) -
keep-alive组件实现缓存(在频繁切换时,可以加快反应速度)
<!--例子,点击按钮,切换登录方式--> <body> <div id="app"> <button @click="typechange">点击切换登录方式</button> <keep-alive> <component :is="type"></component> </keep-alive> </div> <template id="phonelogin"> <div>手机号登录</div> </template> </body> <script src="vue.js"></script> <script> Vue.component('userlogin',{//全局组件 template:'<div>账号密码登录</div>' }) new Vue({ el: '#app', data:{ type:'phonelogin' }, methods: { typechange () { this.type=(this.type==='phonelogin')&&'userlogin'||'phonelogin' } }, components:{//局部组件 'phonelogin':{ template:'#phonelogin' } } }) </script>
-
5、组件嵌套:(子组件以标签的形式要在父组件的模板中使用)
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<!-- 唯一根元素div -->
<div>
<h3> 这里是父组件 </h3>
<hr>
<Son></Son><!--子组件以标签的形式要在父组件的**模板中**使用-->
</div>
</template>
<template id="son">
<div>
<h3> 这里是子组件 </h3>
</div>
</template>
</body>
<script>
//1、全局注册
Vue.component('Father',{
template: '#father'
})
Vue.component('Son',{
template: '#son'
})
new Vue({
el: '#app'
})
</script>
<script>
//2、局部注册,注意这里的组件注册的写法,子组件是在父组件里面注册的
new Vue({
el: '#app',
components: {
'Father': {
template: '#father',
components: {
'Son': {
template: '#son'
}
}
}
}
})
</script>
6、组件中的数据
1. 为什么组件中的data选项是一个函数,而根实例中是对象?
原因:
1. 组件是一个独立的整体,那么数据也应该是一个独立的
2. 多人开发,数据如果不是独立的,那么数据会冲突
3. javascript最大的特点: 函数式编程,而函数本身就有一个独立作用域
2. 为什么组件中的data函数要有返回值,并且返回值是一个对象,不能是其他的吗?
原因:
1. 因为data选项要经过es5的Object.defineProperty 属性进行getter和setter设置,
如果不是对象,就不能进行后续操作
3. 数据中数据的使用
组件的数据,使用范围只能在组件的模板中
Vue.component('Hello',{
template: '#hello',
data () {
return {//要有返回值
msg: '今天热的要死' // 组件的数据,使用范围只能在组件的模板中
}
}
})
new Vue({
el: '#app'
})
7、组件通信:
-
父子组件通信:(利用props)
<body> <div id="app"> <Father/> </div> <!-- father 组件 --start --> <template id="father"> <div> <h3> 这里是父组件 </h3> <Son :aa = "money"></Son><!--在父组件的模板中,用 v-bind 将父组件的数据绑定在子组件身上--> </div> </template> <!-- father 组件 --end --> <!-- son组件 --start --> <template id="son"> <div> <h4> 这里是子组件 </h4> <p> 老爸给了我 {{ aa }} 生活费 </p> </div> </template> <!-- son组件 --end --> </body> <script src="vue.js"></script> <script> /* 父子组件通信 1. 父组件中定义一个数据 2. 在父组件的模板中,用 v-bind 将父组件的数据绑定在子组件身上 <Son :aa = "money"></Son>,aa为自定义的一个属性 3. 在子组件的选项中,通过props选项来接收这个属性 4. 这个属性可以在子组件的模板中以全局变量的形式使用 */ Vue.component('Father',{ template: '#father', data () { return { money: 3000 } } }) Vue.component('Son',{ template: '#son', props: ['aa']//子组件用props来接收 //下面还可以做相关属性验证 // props: { // 'aa': Number //属性验证 // } // props: { // 'aa': { // validator ( val ) { // return val > 2000 // } // } // } }) new Vue({ el: '#app' }) </script>
-
子父组件通信:(利用父组件的自定义事件)
//子父通信流程 //1. 先在子组件中定义一个数据 Vue.component('Son',{ template: '#son', data () { return { money: 1000 } } }) //2. 在父组件中也定义一个数据,这个数据用来接收子组件传递过来的数据 Vue.component('Father',{ template: '#father', data () { return { bank: null } } }) //3. 在父组件中定义一个事件处理程序,用于改变父组件定义的数据, //这个事件处理程序是有参数的,这个参数就是子组件传递过来的数据 Vue.component('Father',{ template: '#father', data () { return { bank: null } }, methods: { bankAdd ( val ) { //val就是子组件给的数据 this.bank += val } } }) //4. 将这个事件处理程序通过自定义事件绑定的形式绑定在子组件身上 <Son @aa = "bankAdd"></Son> //5. 在子组件中定义一个事件处理程序,这事件处理程序中通过 // this.$emit来触发自定义事件,并传递一个参数给父组件 Vue.component('Son',{ template: '#son', data () { return { money: 1000 } }, methods: { give () { // this.$emit('aa',传递给父组件的参数) this.$emit('aa',this.money) } } }) //6、触发子组件身上的事件就触发了父组件身上的自定义事件 <template id="son"> <div> <h4> 这里是子组件 </h4> <button @click = " give "> 给老爸红包 </button> </div> </template>
-
非父子组件通信:(利用 ref 链和bus事件总线)
<!--ref链:--> <!--只能son的数据控制自己,而son通过ref和id将自己的一些方法和数据绑定在了 父组件的Vuecomponent上,再在父组件的模板中,以属性绑定的形式将这个可以 控制son组件数据的方法绑定在了girl组件上,girl可以通过父子组件通信的方法以 props来接收,那么这个方法也在girl上了,这时再触发这个事件,girl就可以控制 son了--> <body> <div id="app"> <Father></Father> </div> <template id="father"> <div><!--唯一根元素--> <h3>这里是father组件</h3> <button @click="print">输出this</button> <hr> <Girl :cry="emitflagchange"></Girl> <hr> <Son ref="son"></Son><!--这里是ref绑定的为id--> </div> </template <template id="girl"> <div> <h3>这里是girl组件</h3> <button @click="cry">姐姐揍弟弟</button> </div> </template> <template id="son"> <div> <h3>这里是son组件</h3> <button @click="flagchange">自己揍自己</button> <br> <img v-show="flag" style = "width: 100px;height: 100px;" src="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1564471527&di=2c4707955cefb24c325842ea288b9647&src=http://b-ssl.duitang.com/uploads/item/201702/16/20170216145320_wyNiK.jpeg" alt=""> </div> </template> </body> <script src="../../lib/vue.js"></script> <script> Vue.component('Father',{ template:'#father', data () { return { } }, methods:{ print () { console.log(this.$refs.son) }, emitflagchange () { this.$refs.son.flagchange() } } }) Vue.component('Girl',{ template:'#girl', data () { return { } }, props:['cry'],//接收父组件传来的数据 methods:{ p () { console.log(this) } } }) Vue.component('Son',{ template:'#son', data () { return { flag:false } }, methods: { flagchange () { this.flag=!this.flag } } }) new Vue({ el: '#app' }) </script>
//bus事件总线 <body> <div id="app"> <Girl></Girl> <Son></Son> </div> <template id="girl"> <div> <h3>这里是girl组件</h3> <button @click="hit">揍弟弟</button> </div> </template> <template id="son"> <div> <h3>这里是son组件</h3> <button @click="cry">自己揍自己</button> <br> <img style = "width: 100px;height: 100px;" v-show = "flag" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564481613744&di=22ebae5b3c4655691a1244e46682d7c9&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201702%2F16%2F20170216145320_wyNiK.jpeg" alt=""> </div> </template> </body> <script src="../../lib/vue.js"></script> <script> var bus = new Vue()//用bus将两个组件串联起来 console.log(bus) Vue.component('Girl',{ template:'#girl', methods:{ hit () { bus.$emit('abc') } } }) Vue.component('Son',{ template:'#son', data () { return { flag:true } }, methods:{ cry () { this.flag=!this.flag } }, mounted() { var _this=this//保存this,因为this到下面函数里会变化 // bus.$on(自定义事件的名称,自定义事件的处理程序) bus.$on('abc',function(){// 通过$on自定义一个叫做abc的事件 _this.cry() }) }, }) new Vue({ el: '#app' }) </script>