1、组件的嵌套
利用脚手架创建一个项目。vue create 项目名
如果将所有逻辑都放在一个组件中,这个组件就会变得非常臃肿和难以维护。 组件化的核心思想是对组件进行拆分,再将这些拆分的组件嵌套在一起,最终形成应用程序。
2、组件的拆分
app:Header 、Main、Footer Main: Banner、ProductList 各个部分还可以进行细化拆分。 拆分后开发对应的逻辑只需要去对应的组件编写就可。
<template>
<div id="app">
<headert></headert>
<Maint></Maint>
<footert></footert>
</div>
</template>
<script>
// 导入三个组件
import Headert from "./Headert.vue";
import Maint from "./Maint.vue";
import Footert from "./Footert.vue";
export default{
data() {
return{
}
},
// 注册组件
components : {
Headert,
Maint,
Footert
}
}
</script>
<!-- scoped使得当前组件中的样式对于外部不产生影响 -->
<style scoped>
</style>
3.组件的CSS作用域
通过scoped防止组件与组件之间的样式污染。
<template>
<h2>Vue</h2>
<hello-world></hello-world>>
</template>
<script>
import HelloWorld from "./HelloWorld.vue"
export default {
components : {
HelloWorld
}
}
</script>
<style scoped>
h2{
color: pink;
}
</style>
4.组件的通信
- 比如App中可能用来多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递个Header一些数据,让它进行展示;
- 比如Main中一次性请求了Banner数据和ProductList数据,就需要传递给他们来进行展示。
- 子组件中发生了事件,需要由父组件来完成某些操作,就需要子组件向父组件传递事件;
5.父子组件之间的通信方式
父组件传递给子组件 通props属性来完成组件之间的通信。
什么是props?
props是可以在组件上注册一些自定义的attribute; 父组件给这些attribute赋值,子组件通过attribute的名称获得对应的值。
props两种常见用法:
方式一:字符串数组,数组中的字符串就是attribute的名称。
//在子组件中先定义
export default{
props :[ 'title','content']
data(){
return{
}
}
}
<hello-world title="hhh" content="我是哈哈哈哈"></hello-world>
结果:
方式二:对象类型 ,
export default{
props:{
title : String,
content :{
// 设置传入的类型
type : String ,
// 必传项
required : true ,
// 默认值为"abc",与require不能同时使用
// default : 'abc'
}
},
}
传入的类型type可以有哪些? String、Number、Boolean、Array、Object、Date、Function、Symbol等
当type类型为Object的时候,值得是一个函数。
content :{
type :Object,
default(){
return{
name:'phoebe'
}
}
}
非Prop的attribute 产地给某个组件一个属性,没有在Prop或者$emit中定义,称之为非Prop的attribute。 常见的包括class、id、style等
Attribute的继承 当组件有单个根节点时,非Prop的attribute将自动添加到根节点的Attribute中 禁用attribute继承 在组件中设置export default{ inheritAttrs :false} 将Attribute应用于根元素之外的其他元素<h2 :class="$attrs.class">Hello world</h2> 通过:class="$attrs.class来访问需要访问的非Props的attribute
子组件传递给父组件 通过$emit触发事件 计数器,输入数字计数器加这个数字,点击加减按钮计数器加减。
子组件:
<template>
<button @click="subcreate">+1</button>
<button @click="decreate">-1</button>
<input type="text" v-model.number="num">
<button @click="subcreateN">+N</button>
</template>
<script>
export default{
emits:["add" ,"sub","addN"],
data(){
return {
num:0
}
},
methods:{
subcreate(){
console.log("+1")
this.$emit("add")
},
decreate(){
console.log("-1")
this.$emit("sub")
},
subcreateN(){
this.$emit("addN",this.num)
}
}
}
</script>
父组件:
<template>
<h2>当前数值{{counter}}</h2>
<counter @add="addOne" @sub="subOne" @addN="addN"></counter>
</template>
<script>
import Counter from "./Counter.vue"
export default {
components : {
Counter
},
data(){
return {
counter :0
}
},
methods:{
addOne(){
this.counter++
},
subOne(){
this.counter--
},
addN(num){
this.counter+= num
}
}
}
</script>
注册emits也可以写成对象形式,为了验证参数。
6、商品栏切换案例
<template>
<div >
<tabchange :titles="titles" @titlechange="titlechange"></tabchange>
<h2>{{contents[currentIndex]}}</h2>
</div>
</template>
<script>
import Tabchange from "./Tabchange.vue"
export default {
components : {
Tabchange
},
data(){
return {
titles:["衣服","裤子","鞋子"],
contents :["衣服页面","裤子页面","鞋子页面"],
currentIndex :0
}
},
methods:{
titlechange(index){
this.currentIndex =index;
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="tab-control">
<div class="tab-title"
:class="{active:currentIndex===index}"
v-for="(title ,index) in titles"
:key="title"
@click="change(index)">
<span >
{{title}}
</span>
</div>
</div>
</template>
<script>
export default{
emits :["titlechange"],
props :{
titles:Array,
default(){
return []
}
},
data(){
return{
currentIndex:0
}
},
methods:{
change(index){
this.currentIndex =index,
this.$emit("titlechange",index)
}
}
}
</script>
<style scoped>
.tab-control{
display: flex;
}
.tab-title{
flex: 1;
text-align: center;
}
.active{
color: red;
/* border-bottom: 3px solid red;
padding: 5px 8px; */
}
.active span{
border-bottom: 3px solid red;
padding: 5px 8px;
}
</style>
|