1.注册组件就是利用Vue.component()方法
2.能够理解为一个vue文件就是一个组件html
组件的模板中只能有一个根元素vue
var app = new Vue({ data () { return { message: 'hello world' } } })
例,一个父组件:数组
<my-component v-bind:foo="baz" v-on:event-a="doThis(arg1,...arg2)"></my-component>
上面代码app
foo
是<my-component>
组件内部定义的一个prop
属性,baz
是父组件的一个data属性,event-a
是子组件定义的一个事件,doThis
是父组件的一个方法执行过程应该是这样的:函数
baz
数据经过prop
传递给子组件的foo
;foo
的值,就能够进行相应的操做;event-a
事件,把一些数据发送出去doThis
方法,子组件发送的数据,就做为doThis
方法的参数被传进来Vue组件经过props
属性来声明一个本身的属性,而后父组件就能够往里面传递数据。ui
Vue.component('mycomponent',{ template: '<div>这是一个自定义组件,父组件传给个人内容是:{{myMessage}}</div>', props: ['myMessage'], data () { return { message: 'hello world' } } })
而后调用该组件this
<div id="app"> <mycomponent my-message="hello"></mycomponent> </div>
注意,因为HTML特性是不区分大小写的,因此传递属性值时,myMessage
应该转换成 kebab-case (短横线隔开式)my-message="hello"
。spa
<div attr="message">hello</div>
上面这样,div
元素的attr
特性值就是message
。而这样双向绑定
<div v-bind:attr="message">hello</div>
这里的message
应该是Vue实例的data的一个属性,这样div
元素的attr
特性值就是message
这个属性的值。
之因此说是通常状况,是由于class
和style
特性并非这样。用v-bind:class
和class
传入正常的类名,效果是同样的,由于对于这两个特性,Vue采用了合并而不是替换的原则。code
根据上面,想要把父组件的属性绑定到子组件,应该使用v-bind
,这样,父组件中数据改变时能反映到子组件。
注意 在子组件中最好不要更改父组件传入的值,若是非要更改的话,加上.sync
修饰符
例父组件
<my-component :child-array.sync="parentArray"></my-component>
子组件
methods: { changeArray () { this.counter++ this.$emit('update:childArray', this.counter) } }
一样是上面的缘由,静态的给子组件的特性传递值,它都会把他当作一个字符串。
<!-- 传递了一个字符串 "1" --> <comp some-prop="1"></comp>
子组件中,特性的值是字符串 "1" 而不是 number 1。若是想传递正确的数值,应该使用v-bind传递,这样就能把传递的值当作一个表达式来处理,而不是字符串。
<!-- 传递实际的 number 1 --> <comp v-bind:some-prop="1"></comp>
咱们能够给组件的props
属性添加验证,当传入的数据不符合要求时,Vue会发出警告。
Vue.component('example', { props: { // 基础类型检测 (`null` 意思是任何类型均可以) propA: Number, // 多种类型 propB: [String, Number], // 必传且是字符串 propC: { type: String, required: true }, // 数字,有默认值 propD: { type: Number, default: 100 }, // 数组/对象的默认值应当由一个工厂函数返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { return value > 10 } } } })
type
能够是下面原生构造器:
type
也能够是一个自定义构造器函数
经过prop属性,父组件能够向子组件传递数据,而自定义事件就是用来将子组件的内部数据报告给父组件的。
例
<div id="app3"> <my-component2 v-on:myclick="onClick"></my-component2> </div> <script> Vue.component('my-component2', { template: `<div> <button type="button" @click="childClick">点击我触发自定义事件</button> </div>`, methods: { childClick () { this.$emit('myclick', '这是我暴露出去的数据', '这是我暴露出去的数据2') } } }) new Vue({ el: '#app3', methods: { onClick () { console.log(arguments) } } }) </script>
如上所示,共分为如下步骤:
子组件在本身的方法中将自定义事件以及须要发出的数据经过如下代码发送出去
this.$emit('myclick', '这是我暴露出去的数据', '这是我暴露出去的数据2')
第一个参数是自定义事件的名字 后面的参数是依次想要发送出去的数据
父组件利用v-on
为事件绑定处理器
<my-component2 v-on:myclick="onClick"></my-component2>
这样,在Vue实例的methods
方法中就能够调用传进来的参数了
注意: 在使用v-on
绑定事件处理方法时,不该该传进任何参数,而是直接写v-on:myclick="onClick"
,否则,子组件暴露出来的数据就没法获取到了
若是想在某个组件的根元素上监听一个原生事件。可使用 .native
修饰 v-on
v-model
v-model
能够对表单控件实现数据的双向绑定,它的原理就是利用了绑定属性和事件来实现的。好比input
控件。不使用v-model
,能够这样实现数据的双向绑定:
<div id="app4"> <input type="text" v-bind:value="text" v-on:input="changeValue($event.target.value)"> {{text}} </div> <script> new Vue({ el: '#app4', data: { text: '444' }, methods: { changeValue (value) { this.text = value } } }) </script>
上面的代码一样实现了数据的双向绑定。其本质就是:
input
的value
特性绑定到Vue实例的属性text
上,text
改变,input
中的内容也会改变input
事件处理函数设置为Vue实例的一个方法,这个方法会根据输入参数改变Vue中text
的值input
中输入内容时,触发了input
事件,把event.target.value
传给这个方法,最后就实现了改变绑定的数据的效果。而v-model
就是上面这种方式的语法糖,也就是把上面的写法封装了一下,方便咱们使用。
上面用到的不少组件的使用方式是这样的:
<component></component>
也就是说组件中是空的,没有放置任何文本或元素。可是原生的html元素都是能够进行嵌套的,div
里面放table
什么的。自定义组件开闭标签之间也能够放置内容,不过须要在定义组件时使用slot
。
slot
至关于子组件设置了一个地方,若是在调用它的时候,往它的开闭标签之间放了东西,那么它就把这些东西放到slot
中。
子组件的模板:
<div> <h2>我是子组件的标题</h2> <slot> 只有在没有要分发的内容时才会显示。 </slot> </div>
父组件模板:
<div> <h1>我是父组件的标题</h1> <my-component> <p>这是一些初始内容</p> </my-component> </div>
渲染结果:
<div> <h1>我是父组件的标题</h1> <div> <h2>我是子组件的标题</h2> <p>这是一些初始内容</p> </div> </div>
slot
能够有不少个。那么子组件对于父组件放置的多余的内容如何放到各个slot
中呢?方法就是子组件给每一个slot
起一个名字name
,父组件放置多余的元素时,给每一个元素的slot
属性分配一个表明slot
的名字。到时候,多余的内容就会根据本身的slot
属性去找具备对应名字的slot
元素。
注意:
例如,假定咱们有一个 app-layout 组件,它的模板为:
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
父组件模版:
<app-layout> <h1 slot="header">这里多是一个页面标题</h1> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> <p slot="footer">这里有一些联系信息</p> </app-layout>
渲染结果为:
<div class="container"> <header> <h1>这里多是一个页面标题</h1> </header> <main> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> </main> <footer> <p>这里有一些联系信息</p> </footer> </div>
做用域插槽也是一个插槽slot
,可是他能够把数据传递给到父组件的特定元素内,而后有父组件决定如何渲染这些数据。
首先,子组件的slot
须要有一些特性(prop)
Vue.component('my-component4', { template: `<div> <slot :text="hello" message="world"></slot> </div>`, data () { return { hello: [1,'2'] } } })
父组件在调用子组件时,须要在里面添加一个template
元素,而且这个template
元素具备scope
特性
<div id="app7"> <my-component4> <template scope="props"> </template> </my-component4> </div>
scope
特性的值,就表明了全部子组件传过来的数据组成的对象。至关于
props = { text: '', message: '' }
最后,父组件就能够在template
中渲染子组件传过来的数据了
<div id="app7"> <my-component4> <template slot-scope="props"> <span>{{props.text}}</span> <span>{{props.message}}</span> </template> </my-component4> </div>
做用域插槽也是插槽,只不过是多加了些特性,而后父组件多进行了些处理。