1. component basicconcepts
component is Vue.jsapplication basic构建块, 它允许我们将UI拆分 for 独立 , 可复用 module. 每个component都package含自己 模板, 逻辑 and 样式.
1.1 component 优势
- reusability: component可以 in 不同 页面 and 场景in重复using.
- 可maintenance性: 每个component专注于单一functions, 便于maintenance and update.
- 可test性: component可以独立fortest.
- 协作Development: team members可以同时Development不同 component, improvingDevelopmentefficiency.
2. component register
Vuecomponent需要先register才能using. componentregister has 两种方式: 全局register and 局部register.
2.1 全局register
全局register component可以 in 任何Vueinstance 模板inusing.
// 全局registercomponent
Vue.component('my-component', {
// component选项
template: '<div>这 is a 全局component</div>',
data: function() {
return {
count: 0
};
},
methods: {
increment: function() {
this.count++;
}
}
});
2.2 局部register
局部register component只能 in register它 父componentinusing.
// 定义component
var MyComponent = {
template: '<div>这 is a 局部component</div>',
data: function() {
return {
count: 0
};
},
methods: {
increment: function() {
this.count++;
}
}
};
// in Vueinstanceinregister局部component
var app = new Vue({
el: '#app',
components: {
'my-component': MyComponent
}
});
2.3 componentregister Notes
- component名称应该usingkebab-case ( short 横线分隔) or PascalCase (首字母 big 写) .
- in 模板inusingkebab-case引用component.
- component data选项必须 is a function, 这样每个componentinstance才能拥 has 独立 datareplica.
- 全局register component会 in Vueinstance化之 before 就被register, 所以不能访问Vueinstance data.
3. component 模板
component 模板定义了component HTMLstructure.
3.1 in 联模板
可以直接 in component选项inusingtemplateproperty定义 in 联模板.
Vue.component('my-component', {
template: '<div class="my-component">
<h3>{{ title }}</h3>
<p>{{ content }}</p>
<button @click="increment">点击次数: {{ count }}</button>
</div>',
data: function() {
return {
title: 'component标题',
content: 'component in 容',
count: 0
};
},
methods: {
increment: function() {
this.count++;
}
}
});
3.2 单filecomponent (.vuefile)
in practicalDevelopmentin, 通常using单filecomponent (.vuefile) 来定义component, 这样可以将模板, 脚本 and 样式放 in 同一个filein.
<!-- MyComponent.vue -->
<template>
<div class="my-component">
<h3>{{ title }}</h3>
<p>{{ content }}</p>
<button @click="increment">点击次数: {{ count }}</button>
</div>
</template>
<script>
export default {
data() {
return {
title: 'component标题',
content: 'component in 容',
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
};
</script>
<style scoped>
.my-component {
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 5px;
background-color: #f8f9fa;
}
button {
background-color: #4285F4;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #3367D6;
}
</style>
提示
单filecomponent需要using构建tool (such asWebpack or Vite) for编译才能 in 浏览器inrun.
4. component data and method
component可以拥 has 自己 data and method, and Vueinstanceclass似.
4.1 component data
component data必须 is a function, 这样每个componentinstance才能拥 has 独立 datareplica.
// 正确 做法: data is function
Vue.component('my-component', {
data: function() {
return {
count: 0
};
}
});
// error 做法: data is object
Vue.component('my-component', {
data: {
count: 0
}
});
4.2 component method
component method定义 in methods选项in, and Vueinstance methodsclass似.
Vue.component('counter-component', {
template: '<div>
<p>当 before 计数: {{ count }}</p>
<button @click="increment">增加</button>
<button @click="decrement">reducing</button>
<button @click="reset">reset</button>
</div>',
data: function() {
return {
count: 0
};
},
methods: {
increment: function() {
this.count++;
},
decrement: function() {
this.count--;
},
reset: function() {
this.count = 0;
}
}
});
5. component 生命周期
component 生命周期 and Vueinstance 生命周期class似, 但 has 一些specific hookfunction.
5.1 component 生命周期hook
- beforeCreate: componentinstancecreation before 调用, 此时data and methods还未初始化.
- created: componentinstancecreation after 调用, 此时data and methods已初始化, 但DOM还未挂载.
- beforeMount: DOM挂载 before 调用, 此时模板已编译, 但还未挂载 to DOM on .
- mounted: DOM挂载 after 调用, 此时模板已挂载 to DOM on , 可以访问DOM元素.
- beforeUpdate: dataupdate before 调用, 此时data已update, 但DOM还未update.
- updated: dataupdate after 调用, 此时data and DOM都已update.
- beforeDestroy: component销毁 before 调用, 此时component仍然可用.
- destroyed: component销毁 after 调用, 此时component已不可用.
- activated: (仅用于keep-alivecomponent) component被激活时调用.
- deactivated: (仅用于keep-alivecomponent) component被停用时调用.
Vue.component('life-cycle-component', {
template: '<div>
<p>当 before 计数: {{ count }}</p>
<button @click="increment">增加</button>
</div>',
data: function() {
return {
count: 0
};
},
methods: {
increment: function() {
this.count++;
}
},
beforeCreate: function() {
console.log('component beforeCreate hook');
},
created: function() {
console.log('component created hook');
},
beforeMount: function() {
console.log('component beforeMount hook');
},
mounted: function() {
console.log('component mounted hook');
},
beforeUpdate: function() {
console.log('component beforeUpdate hook');
},
updated: function() {
console.log('component updated hook');
},
beforeDestroy: function() {
console.log('component beforeDestroy hook');
},
destroyed: function() {
console.log('component destroyed hook');
}
});
5.2 生命周期 application场景
- created: 适合fordata初始化, APIrequestetc.operation.
- mounted: 适合forDOMoperation, 第三方library初始化etc.operation.
- updated: 适合 in dataupdate after 执行DOMoperation.
- beforeDestroy: 适合forclean工作, such as清除定时器, 取消event监听etc..
6. component props
props is 父component向子component传递data 方式.
6.1 basicusing
// 子component
Vue.component('child-component', {
// 定义props
props: ['message', 'count'],
template: '<div>
<p>父component传递 message: {{ message }}</p>
<p>父component传递 计数: {{ count }}</p>
</div>'
});
// 父component
var app = new Vue({
el: '#app',
data: {
parentMessage: 'Hello from parent',
parentCount: 100
}
});
<!-- in 父component模板inusing子component -->
<div id="app">
<child-component
:message="parentMessage"
:count="parentCount">
</child-component>
</div>
6.2 props class型validation
可以 for props指定class型, Vue会 in Developmentenvironmentinforclass型validation.
Vue.component('child-component', {
props: {
// Basicsclass型check
message: String,
count: Number,
isActive: Boolean,
items: Array,
config: Object,
callback: Function,
date: Date,
// 带默认值 props
defaultMessage: {
type: String,
default: 'Default message'
},
// 带默认值 object or array
defaultItems: {
type: Array,
default: function() {
return [1, 2, 3];
}
},
// 必填项
requiredProp: {
type: String,
required: true
},
// 自定义verificationfunction
customProp: {
validator: function(value) {
return value > 0;
}
}
},
template: '<div>...</div>'
});
warning
props is 单向data流, 子component不应该直接modify父component传递 props. such as果需要modify, 应该througheventnotification父componentformodify.
7. component event
子component可以throughevent向父component发送message.
7.1 自定义event
// 子component
Vue.component('child-component', {
template: '<div>
<button @click="sendMessage">向父component发送message</button>
</div>',
methods: {
sendMessage: function() {
// using$emit触发自定义event
this.$emit('child-event', 'Hello from child', 123);
}
}
});
// 父component
var app = new Vue({
el: '#app',
methods: {
handleChildEvent: function(message, data) {
console.log('收 to 子component message:', message, data);
}
}
});
<!-- in 父component模板in监听子componentevent -->
<div id="app">
<child-component @child-event="handleChildEvent"></child-component>
</div>
7.2 event修饰符
Vueproviding了一些event修饰符, 用于简化eventprocessing逻辑.
- .stop: 阻止event冒泡
- .prevent: 阻止默认event
- .capture: usingevent捕获模式
- .self: 只当event in 该元素本身触发时才触发processingfunction
- .once: event只触发一次
- .passive: 告诉浏览器该event监听器不会调用preventDefault()
<!-- 阻止event冒泡 -->
<div @click.stop="handleClick">点击</div>
<!-- 阻止默认event -->
<form @submit.prevent="handleSubmit">
<button type="submit">submitting</button>
</form>
<!-- event只触发一次 -->
<button @click.once="handleClickOnce">只点击一次</button>
8. component 插槽
插槽允许父component向子component 指定位置插入 in 容.
8.1 basic插槽
// 子component
Vue.component('child-component', {
template: '<div class="child">
<h3>子component标题</h3>
<slot>默认 in 容</slot>
<p>子component底部</p>
</div>'
});
<!-- in 父componentinusing插槽 -->
<div id="app">
<child-component>
<p>这 is 插入 to 子component插槽in in 容</p>
</child-component>
<child-component>
<ul>
<li>list项1</li>
<li>list项2</li>
<li>list项3</li>
</ul>
</child-component>
</div>
8.2 具名插槽
具名插槽允许 in 子componentin定义 many 个插槽, 父component可以向不同 插槽插入 in 容.
// 子component
Vue.component('layout-component', {
template: '<div class="layout">
<header>
<slot name="header">默认头部</slot>
</header>
<main>
<slot>默认 in 容</slot>
</main>
<footer>
<slot name="footer">默认底部</slot>
</footer>
</div>'
});
<!-- in 父componentinusing具名插槽 -->
<div id="app">
<layout-component>
<template v-slot:header>
<h1>自定义头部</h1>
</template>
<template v-slot:default>
<p>自定义 in 容</p>
<p>更 many in 容</p>
</template>
<template v-slot:footer>
<p>自定义底部</p>
</template>
</layout-component>
</div>
提示
v-slot可以缩写 for #, 例such asv-slot:header可以缩写 for #header.
8.3 作用域插槽
作用域插槽允许子component向父component传递data, 父component可以using这些data来渲染插槽 in 容.
// 子component
Vue.component('list-component', {
data: function() {
return {
items: ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
};
},
template: '<div class="list">
<h3>水果list</h3>
<ul>
<li v-for="(item, index) in items" :key="index">
<slot :item="item" :index="index">
{{ item }}
</slot>
</li>
</ul>
</div>'
});
<!-- in 父componentinusing作用域插槽 -->
<div id="app">
<list-component>
<template v-slot="slotProps">
<strong>{{ slotProps.index + 1 }}. {{ slotProps.item }}</strong>
</template>
</list-component>
<list-component>
<template v-slot:default="{ item, index }">
<span style="color: red;">{{ index + 1 }}. {{ item }}</span>
</template>
</list-component>
</div>
练习 1: creation and usingcomponent
- creation一个全局component, 用于显示userinformation (package含姓名, 年龄, 性别) .
- creation一个局部component, 用于显示商品list (package含商品名称, 价格, describes) .
- in Vueinstanceinusing这两个component.
- for component添加适当 样式.
练习 2: component间通信
- creation一个父component and 一个子component.
- 父component向子component传递data (usingprops) .
- 子component向父component发送event (using$emit) .
- implementation一个 simple 计数器functions:
- 子component显示计数 and 增加按钮
- 点击增加按钮, 子component向父component发送event
- 父componentupdate计数, 并throughprops传递给子component
练习 3: using插槽
- creation一个卡片component, package含头部, in 容 and 底部三个插槽.
- in 父componentinusing该卡片component, 向不同 插槽插入 in 容.
- for 卡片component添加适当 样式, 使其看起来像一个真正 卡片.
- creation一个listcomponent, using作用域插槽向父component传递list项data.
- in 父componentinusing作用域插槽自定义list项 渲染方式.