组件简单来说就是将代码封装,便于后续重复使用,被封装的代码可以包含多种例如 html、css、js。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
流程
new Vue
创建的 Vue 根实例,组件代码需要在根代码前Vue.component(tagName, options)
注册组件,tagName 为组件名,options 为配置选项<组件名></组件名>
<div id="app">
<child></child>
</div>
<script>
Vue.component('Child', {
template: `
<div>
<p><input type="text" v-model="name"> {{ name }}</p>
<p><input type="button" @click="func"></p>
</div>
`,
data() {
return {
name: '',
}
},
methods: {
func() {
console.log('这是全局组件')
}
}
})
var vm = new Vue({
el: '#app',
data: {
name: 'xwx'
},
methods: {},
computed: {},
})
</script>
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子
等。除了像 el
这样根实例特有的选项。
还有需要注意的是 data
必须是函数。
局部注册可以写在 Vue 实例或者 组件实例中。
<div id="app">
<child></child>
</div>
<script>
var vm = new Vue({
el: '#app',
components: {
'Child': {
template: `<div>这是局部组件</div>`
}
}
})
</script>
或
Vue.component('navbar', {
template: `
<div>
<p>全局组件</p>
<child></child>
</div>
`,
components: {
child: {
template: `<p>局部组件</p>`,
}
}
})
注意点:局部注册的子组件只能在已经注册过的父组件中使用,也可以多层嵌套
组件之间数据默认不互通,如下所示
<div id="app">
<one></one>
</div>
<script>
var two = {
template: `<p>局部组件{{name}}</p>`,
data() {
return {
'name': 'zzz'
}
},
}
Vue.component('one', {
template: `
<div>
<p>全局组件{{name}}</p>
<two></two>
</div>
`,
data() {
return {
'name': 'xwx'
}
},
components: {
'two': two
}
})
var vm = new Vue({
el: '#app',
})
</script>
此时可以将全局看成是父,局部是子
<div id="app">
<one></one>
</div>
<script>
var two = {
props: ['message',],
template: `<p>局部组件-----{{ message }}</p>`,
}
Vue.component('one', {
template: `
<div>
<p>全局组件--{{ name }}</p>
<two :message="name"></two>
</div>
`,
data() {
return {
name: 'xwx'
}
},
components: {
'two': two
}
})
var vm = new Vue({
el: '#app',
})
</script>
<div id="app">
<one :message="name"></one>
</div>
<script>
Vue.component('one', {
template: `
<div>
<p>全局组件-----{{ message }}</p>
</div>
`,
props: ['message',]
})
var vm = new Vue({
el: '#app',
data: {
name: 'xwx'
}
})
</script>
props
组件可以为 props 指定验证要求。
可以在子组件中添加定制 prop 的验证方式,将原本的 props: [‘message’,] 修改如下所示
props: {
'message': Number
}
若是类型不符合,虽然会报错,但也会显示出来。
定制的类型如下所示
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口,即:
$on(eventName)
监听事件$emit(eventName)
触发事件<div id="app">
<p>子组件中myfunc的数据是:{{name}}</p>
<one @myfunc="func"></one>
</div>
<script>
Vue.component('one', {
template: `
<div>
<button @click="handleClick">点击按钮把子组件数据传递到父组件</button>
</div>
`,
data() {
return {
name: 'xwx'
}
},
methods: {
handleClick() {
this.$emit('myfunc', this.name)
}
}
})
var vm = new Vue({
el: '#app',
data: {
name: ''
},
methods: {
func(name) {
console.log(123)
this.name = name
}
}
})
</script>
this.$emit('myfunc', this.name)
,myfunc 就是自定义事件,后面的参数就是需要传给绑定的函数的参数,也就是执行了自定义事件的函数<div id="app">
<p ref="p1">xwx</p>
<button @click="handleClick">点我执行函数</button>
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
handleClick() {
this.$refs['p1'].innerHTML = 'XWenXiang'
}
}
})
</script>
上面的例子中,给一个标签添加 'ref' 属性,然后执行函数,从 'this.$refs' 中获取的就是原生节点,
可以使用原生的 DOM 操作
<div id="app">
<one ref="one1"></one>
<p>这是子传父的属性{{name}}</p>
<button @click="handleClick">点我执行函数</button>
</div>
<script>
Vue.component('one', {
template: `
<div></div>
`,
data() {
return {
name: 'xwx'
}
}
})
var vm = new Vue({
el: '#app',
data: {
name: ''
},
methods: {
handleClick() {
// 同理可以调用子组件的函数
this.name = this.$refs['one1'].name
}
}
})
</script>
可以获取子组件的数据,也可以设置子组件的数据
<div id="app">
<one ref="one1"></one>
<button @click="handleClick">点我执行函数</button>
</div>
<script>
Vue.component('one', {
template: `
<div><p>这是父传子的属性{{name}}</p></div>
`,
data() {
return {
name: ''
}
}
})
var vm = new Vue({
el: '#app',
data: {
name: 'xwx'
},
methods: {
handleClick() {
this.$refs['one1'].name = this.name
}
}
})
</script>
事件总线可以对不同层级的不通组件通信
<div id="app">
<one></one>
<two></two>
</div>
<script>
var bus = new Vue()
Vue.component('one', {
template: `
<div>
<button @click="handleClick">点我</button>
</div>
`,
data() {
return {
name: 'xwx'
}
},
methods: {
handleClick() {
bus.$emit('func', this.name)
}
}
})
Vue.component('two', {
template: `
<div>收到的数据是 {{ name }}</div>
`,
data() {
return {
name: ''
}
},
mounted() {
bus.$on('func', (name) => {
this.name = name
})
}
})
var vm = new Vue({
el: '#app',
})
</script>
流程
当有多个组件时,切换起来较为繁琐,使用动态组件可以减轻冗余
Vue 的 <component> 元素加一个特殊的 is attribute 来实现
<component> 元素,动态地绑定多个组件到它的 is 属性
<keep-alive> 保留状态,避免重新渲染,适合表单标签
<div id="app">
<button @click="who='one'">第一个组件</button>
<button @click="who='two'">第二个组件</button>
<button @click="who='three'">第三个组件</button>
<component :is="who">
</component>
</div>
<script>
Vue.component('one', {
template: `
<div style="background: red; width: 265px; height: 200px;"></div>
`,
})
Vue.component('two', {
template: `
<div style="background: green; width: 265px; height: 200px;"></div>
`,
})
Vue.component('three', {
template: `
<div style="background: blue; width: 265px; height: 200px;"></div>
`,
})
var vm = new Vue({
el: '#app',
data: {
who: 'one'
}
})
</script>
流程
is
attribute 可以判断展示哪一个组件,我们只需要修改 is 的值即可。在调用组件的适合使用的是 <组件名></组件名> 的形式,标签内部还可以存放内容,这就是插槽
<div id="app">
<one>你好</one>
</div>
<script>
Vue.component('one', {
template: `
<div>
<slot></slot>
</div>
`,
})
var vm = new Vue({
el: '#app',
data: {}
})
</script>
在标签之间存放的值可以用 <slot></slot> 在组件中表示
当存在多个值的时候,可以添加名称,如下所示
<div id="app">
<one>
<p slot="p1">你</p>
<p slot="p2">好</p>
<p slot="p3">啊</p>
</one>
</div>
<script>
Vue.component('one', {
template: `
<div>
<slot name="p1"></slot>
<slot name="p2"></slot>
<slot name="p3"></slot>
</div>
`,
})
var vm = new Vue({
el: '#app',
data: {}
})
</script>