Vue.js 组件开发详解
Vue 实例与组件概念
通过 new Vue() 创建的对象称为 Vue 实例,也可视为应用的根组件。
使用 Vue.component() 可创建可复用的组件。组件分为两类:
- 全局组件:可在任何地方使用的组件
- 局部组件:仅限于定义其的实例或组件内部使用
组件基本用法
全局组件注册
Vue.component('my-component', {
template: `
<div>
<h2>组件内容</h2>
<sub-component></sub-component>
</div>
`,
data() {
return {
message: '组件数据',
timer: null
}
},
methods: {
// 组件方法定义
},
components: {
'sub-component': {
template: '<p>嵌套组件 - {{ info }}</p>',
data() {
return {
info: '子级信息'
}
}
}
}
})
关键点说明:
- Vue 实例通过
el挂载 DOM 元素,组件则是作为自定义标签使用 template内容需包裹在单一根元素中data必须为函数形式以确保组件复用时数据独立components字段用于注册子组件
组件使用方式
<div id="app">
<!-- 使用已注册的组件 -->
<my-component></my-component>
<!-- 自闭合标签形式 -->
<my-component/>
</div>
<!-- 全局组件可在任意位置使用 -->
<my-component></my-component>
局部组件注册方式
- 直接在组件配置中嵌套定义
- 预先定义对象再引入:
const subItem = { template: '<span>外部定义组件</span>', data() { return {} } } Vue.component('main-comp', { template: '<div><sub-item></sub-item></div>', components: { subItem } })
组件间数据交互
父向子传递数据 (Props)
<div id="root">
<child-comp :info="parentValue"></child-comp>
</div>
<script>
const childComp = {
template: `
<div>
<p>来自父组件:{{ info }}</p>
<p>子组件数据:{{ localData }}</p>
</div>
`,
data() {
return { localData: '子级内容' }
},
props: {
info: String
}
}
new Vue({
el: '#root',
data: { parentValue: '父级消息' },
components: { childComp }
})
</script>
要点:
- props 支持数组或对象形式声明
- 对象形式可指定类型验证
- 使用
:属性名="数据"进行绑定 - 建议使用短横线分隔命名
子向父传递数据 (Events)
<div id="app">
<p>子组件数据:{{ receivedData }}</p>
<child-comp @send-data="processData"></child-comp>
</div>
<script>
const childComp = {
template: `
<div>
<input v-model="inputText">
<button @click="transmitData">发送</button>
</div>
`,
data() {
return { inputText: '' }
},
methods: {
transmitData() {
this.$emit('send-data', this.inputText)
}
}
}
new Vue({
el: '#app',
data: { receivedData: '' },
methods: {
processData(childInfo) {
this.receivedData = childInfo
}
},
components: { childComp }
})
</script>
机制说明:
- 使用
this.$emit('事件名', 数据)触发自定义事件 - 父组件通过
@事件名="处理方法"监听 - 处理方法参数接收子组件传递的数据
双向通信 (Refs)
通过 ref 属性可以直接访问组件或 DOM 元素:
<div id="main">
<p ref="textRef">{{ sharedData }}</p>
<child-comp ref="childRef"></child-comp>
<button @click="exchangeData">获取数据</button>
</div>
<script>
const childComp = {
template: '<input v-model="childInput">',
data() {
return { childInput: '' }
}
}
new Vue({
el: '#main',
data: { sharedData: '' },
methods: {
exchangeData() {
this.sharedData = this.$refs.childRef.childInput
console.log(this.$refs)
}
},
components: { childComp }
})
</script>
特点:
- 原生元素的 ref 指向 DOM 对象
- 组件的 ref 指向组件实例对象
- 可直接读取和修改组件数据
高级组件特性
动态组件切换
使用 <component> 标签实现组件动态渲染:
<div id="demo">
<button @click="switchView('compA')">视图A</button>
<button @click="switchView('compB')">视图B</button>
<button @click="switchView('compC')">视图C</button>
<component :is="currentView"></component>
</div>
<script>
const compA = { template: '<h2>界面 A</h2>' }
const compB = { template: '<h2>界面 B</h2>' }
const compC = { template: '<h2>界面 C</h2>' }
new Vue({
el: '#demo',
data: { currentView: 'compA' },
methods: {
switchView(viewName) {
this.currentView = viewName
}
},
components: { compA, compB, compC }
})
</script>
状态保持 (Keep-alive)
<keep-alive>
<component :is="currentView"></component>
</keep-alive>
作用:缓存切换的组件状态,避免重复创建销毁
插槽机制
默认插槽
<div id="test">
<card-comp>
<h3>插入内容</h3>
</card-comp>
</div>
<script>
const cardComp = {
template: `
<div class="card">
<slot></slot>
<hr>
<slot></slot>
</div>
`
}
new Vue({
el: '#test',
components: { cardComp }
})
</script>
具名插槽
<div id="example">
<layout-comp>
<h2>默认区域</h2>
<h2 slot="header">头部内容</h2>
<h2 slot="footer">底部内容</h2>
</layout-comp>
</div>
<script>
const layoutComp = {
template: `
<div>
<slot name="header"></slot>
<hr>
<slot></slot>
<hr>
<slot name="footer"></slot>
</div>
`
}
new Vue({
el: '#example',
components: { layoutComp }
})
</script>