一、组件的两种使用方法
二、使用props传递数据
三、单向数据流
四、组件中的命名方式
五、数据验证
六、组件通信
七、slot(插槽)
八、动态组件
Vue中的组件
- 组件是可复用的Vue实例
- 命名组件推荐使用小写字母,用-连接
- 在组件定义中,除了template,其它选项还有:data,methods,computed
- 组件定义中的data必须是一个方法
一、组件的两种使用方法
全局注册
<my-component>my-component>
Vue.component('my-component',{ template: '组件内容' })
局部注册
var app = new Vue({ el:'#app', components:{ ''my-components:{ template:'组件内容' } } })
二、使用props传递数据
这边的props采用数组方式
父组件向子组件传递数据
v-bin动态绑定父组件传的内容
<div id="app" style="width:300px;height:200px;border:2px solid skyblue"> <child-component msg="我是父组件的内容">child-component> <hr> <input type="text" v-model="dadmsg"> <bind-component :sth="dadmsg">bind-component> div>
var app = new Vue({ el: '#app', data: { dadmsg: 'happy' }, components: { 'child-component': { props: ['msg'], template: '{{msg}}' }, 'bind-component': { props: ['sth'], template: '{{sth}}' } } })
在组件中使用props来从父组件接收参数,在props中的属性,都可以在组件中直接使用。
三、单向数据流
概念理解:通过props传递数据是单向的,父组件变化时数据会传给子组件,但是反过来不行。
目的:是将父子组件解稿,避免子组件修改无意间修改了父组件的状态。
两种改变prop的情况的应用场景
- 父组件传递初始值,子组件可以将它作为初始值保存起来,在自己的作用域下可以随意进行修改;
- 将传递进来的数据作为初始值进行保存
- 注册组件
- 将父组件的数据传递进来,并在子组件中props接收
- 将传递进来的数据通过初始值保存起来
<div id='app'> <child-component msg='今天也要努力啊'>child-component> div>
let app = new Vue({ el: '#app', components: { 'child-component': { props: ['msg'], template: '{{count}}', data() { return { count: this.msg } } } } })
prop作为需要被转变的原始值传入,用计算属性对其再次进行计算
- 注册组件
- 将父组件的数据传递进来,并在子组件中使用props接收
- 将传递进来的数据通过计算属性进行重新计算并渲染到页面
<div id="app"> <input type="text" v-model="width"> <width-component :width='width'>width-component> div>
let app = new Vue({ el: "#app", data: { width: 0 }, components: { 'width-component': { props: ['width'], template: '', computed: { style() { return { width: this.width + 'px', background: 'red', height: '30px' } } } } } })
四、组件中的命名方式
camelCased (驼峰式)
kebabcase(短横线命名)
- 组件中的html中、父组件给子组件传递数据,必须使用短横线命名。 (a-bc √ aBc ×)
- 在props中,短横线命名和驼峰命名都可以。
- 在template中,必须使用驼峰命名,短横线会报错。
- 在data中,使用this.xxx时,必须使用驼峰命名,短横线会报错。
- 组件的命名,短横线命名和驼峰命名都可以。
五、数据验证
这边的props采用对象方式
可验证的类型:Number String Boolean Array Object Function 自定义
<div id="app"> <style-component :a='a' :b='b' :c='c' :d='d' :e='e' :g='g'>style-component> div>
let app = new Vue({ el: '#app', data: { a: 1, b: '2', c: '', //空字符串,就取默认的true d: [111, 222, 333], e: console.log(), g: 3 }, components: { 'styleComponent': { props: { //数字类型 a: { type: Number, required: true //必传 }, //字符串类型 b: { type: [String, Number] }, //布尔类型 c: { type: Boolean, default: true //默认值 }, //数组或对象 默认值是函数形式返回 d: { type: Array, default: function() { return [] } }, //函数类型 e: { type: Function }, //自定义一个函数 g: { validator: function(value) { return value < 10 } } }, template: '{{a}}--{{b}}--{{c}}--{{d}}--{{g}}' } } })
六 、组件通信
子组件向父组件传递数据
——给父组件添加自定义事件
——子组件通过$emit触发事件
- 给父组件添加自定义事件
- 子组件$emit传出数据
- 自定义事件函数接收数据参数并赋值,渲染
<div id="app"> <p>您的账户余额为{{num}}p> <btn-component @change='change'>btn-component> div>
new Vue({ el: '#app', data: { num: 3000 }, methods: { change(value) { this.num = value } }, components: { 'btn-component': { template: '\ \ \', data() { return { count: 3000 } }, methods: { hangle_ad() { this.count += 1000 this.$emit('change', this.count) }, hangle_re() { this.count -= 1000 this.$emit('change', this.count) } } } } })
——v-model代替自定义事件
v-model实质背后做了两个操作
- v-bind绑定一个value属性 (父组件要接收一个value值)
- v-on指令给当前元素绑定input事件 (子组件在有新的value值得时候要触发一个input事件)
所以上面那个银行存款的demo可以改为
<div id="app"> <p>您的账户余额为{{num}}p> <btn-component v-model='num'>btn-component> 这边改啦!! div>
new Vue({ el: '#app', data: { num: 3000 }, //父组件没有自定义函数啦!! components: { 'btn-component': { template: '\ \ \', data() { return { count: 3000 } }, methods: { hangle_ad() { this.count += 1000 this.$emit('input', this.count) //这边改啦!! }, hangle_re() { this.count -= 1000 this.$emit('input', this.count) //这边改啦!! } } } } })
非父组件之间的通信
两个非父子关系的组件进行通信,可以使用一个空的Vue实例作为中央事件总线(中介)
<div id="app"> <ahandle>ahandle> <bhandle>bhandle> div>
var app = new Vue({ el: '#app', data: { bus: new Vue() //bus中介 }, components: { 'ahandle': { template: '', data() { return { aaa: '我是来自a组件的内容' } }, methods: { aclick() { //a组件创建事件,供b组件监听 由bus中介$emit提交 this.$root.bus.$emit('givetob', this.aaa) } } }, 'bhandle': { template: '我是b组件', created() { //b组件监听a组件创建的事件 由bus中介$on监听 this.$root.bus.$on('givetob', function(value) { //这里的value就是a组件传进来的this.aaa alert(value) }) } } } })
父链 $.parent
<div id="app"> <btn-component>btn-component>--{{msg}} div>
let app = new Vue({ el: '#app', data: { msg: '我是父组件,我现在没有内容' }, components: { 'btn-component': { template: '', methods: { changeFather() { this.$parent.msg = '我现在有内容啦' } } } } })
子链 $children
vue提供索引:$ref
<div id="app"> <button @click='getchild'>点击父组件按钮获取a组件内容button> <a-component ref='a'>a-component> 添加索引ref <b-component ref='b'>b-component> {{msg}} div>
let app = new Vue({ el: '#app', data: { msg: '子组件数据未获得' }, methods: { getchild() { this.msg = this.$refs.a.msg //获取a组件的内容 ---refs } }, components: { 'a-component': { template: '', data() { return { msg: '我是a组件中的内容' } } }, 'b-component': { template: '', data() { return { msg: '我是b组件中的内容' } } } } })
七、slot(插槽)
使用slot进行分发内容
编译的作用域
父组件模板的内容在父组件作用域中编译;
子组件模板的内容在子组件作用域内编译。
插槽的用法
混合父组件的内容与子组件自己的模板
- 单个插槽
<div id="app"> <slotcomponent> <p>父组件插入到子组件的内容——我把子组件的slot替换掉啦p> slotcomponent> div>
new Vue({ el: '#app', components: { 'slotcomponent': { template: '父组件没有插入内容没有内容就显示这个 ' } } })
- 具名插槽
<div id="app"> <name-component> <h2 slot="header">标题h2> <p>内容1p> <p>内容2p> <p slot="footer">底部p> name-component> div>
let app = new Vue({ el: '#app', components: { 'name-component': { template: '\' } } })\\\ \\ \\
- 作用域插槽
<div id="app"> <mycomponent> <p slot='aaa' slot-scope='child'> {{child.text}} name拿不到 p> mycomponent> div>
let app = new Vue({ el: '#app', components: { 'mycomponent': { template: '\' } } })\
*2.5.0之前都是用template中写,渲染的是template中的内容
<div id="app"> <mycomponent> <template slot='aaa' slot-scope='child'> {{child.text}} name拿不到 template> mycomponent> div>
访问slot
this.$slot.插槽名称
在具名插槽的例子前提下添加代码
...... components:{ ...... mounted(){ var header = this.$slots.header console.log(header) //此处拿到的是虚拟节点 var headerin = this.$slots.header[0].elm.innerText console.log(headerin) } }
八、动态组件
使用Vue提供的component元素,动态挂载不同的组件
使用is特性来实现
代码
待补充待补充待补充......