Vue 的核心思想之一就是组件化开发,而组件树(Component Tree)则是 Vue 应用的基础结构。
如下图的页面 , 我们将页面组件化 得到右边的组件树
结合上面的图 , 依葫芦画瓢 , 我们用 组件化的思想 , 设计出下面的页面 :
一个实际的页面,将其组件化后得到了一棵包含多个组件的组件树。比如,一个常见的网页布局包含顶部的导航栏、侧边栏、主体内容区域等部分。
我们可以把这些部分分别抽象成AppHeader
、AppAside
、AppMain
、组件 , 再加上AppAside子组件User , AppMain子组件Item,而整个页面则由App
组件来统筹管理这些子组件的组合与交互
抽象为组件树 , 即下面的模式
在 vue devtools 应该呈现出这样的组件树
我的设计思路是 ;
先进行静态页面设计
- APP
- AppHeader
- AppMain
- Item
- AppAside
- User
之后 在 AppMain 再设计 Rate 组件 , 采用父组件向子组件传递信息的方式
- AppMain
-
Rate
-
Item
-
下面按照上面的组件树下代码 :
App
<script setup>
import AppAside from './components/AppAside.vue'
import AppHeader from './components/AppHeader.vue'
import AppMain from './components/AppMain.vue'
</script>
<template>
<!-- LayOut -->
<div class="contaner">
<AppHeader/>
<!-- 布局 : 弹性 -->
<div class="flx">
<AppMain/>
<AppAside/>
</div>
</div>
</template>
<style scoped>
.flx {
display : flex;
}
</style>
导入相关组件
- 在
App.vue
文件中,我们首先导入了AppAside
、AppHeader
和AppMain
组件,以便在模板中使用它们。
模板布局
- 模板中使用
div
元素进行布局,外层的div
设置类为contaner
,内部AppHeader
独占一行,接着是一个类为flx
的div
,在这个弹性布局容器中,AppMain
和AppAside
并列排放,并且AppMain
会占据剩余空间(通过flex: 1
设置)。
AppHeader
<template>
<Header>
Header
</Header>
</template>
<script setup>
</script>
<style scoped>
header {
height : 100px;
background-color: #37372c;
}
</style>
模板内容
- 模板非常简单,只有一个
Header
标签,用于显示页面头部的内容,比如网站的 logo、标题等。
样式设置
- 样式中设置了背景颜色为
#37372c
,高度为 100px,给头部一个明确的视觉效果。
AppMain
在该组件里 , 父组件是 AppMain , 子组件是 Item
<template>
<main>
Main
<Item/>
<Item/>
</main>
</template>
<script setup>
import Item from './Item.vue'
import {ref} from 'vue'
</script>
<style scoped>
main {
flex : 1;
height: 500px;
background-color: rgb(136, 111, 137);
}
</style>
Item
<template>
<div>
Item
</div>
</template>
<script setup>
</script>
<style scoped>
div{
height:100px;
background-color: aquamarine;
margin:10px;
}
</style>
模板展示
- 模板中是一个简单的
div
标签,用于显示具体的项目内容,比如列表项、文章摘要等。
样式调整
- 样式中设置
div
高度为 100px,背景颜色为aquamarine
,外边距为 10px,使每个项目在页面上有一定的间隔和视觉区分。
AppAside
<template>
<aside class = "flx">
Aside
<User/>
<User/>
<User/>
</aside>
</template>
<script setup>
import User from './User.vue'
</script>
<style scoped>
aside{
width:200px;
height:500px;
background-color: rgb(109, 90, 54);
}
</style>
导入用户组件
- 导入
User
组件,因为侧边栏可能会展示用户相关信息或其他导航链接等内容。
模板布局
- 模板中是一个
aside
标签,内部包含三个User
组件,使用在App
组件中定义的flx
类进行布局,使User
组件在侧边栏中按一定方式排列。
User
<template>
<div>
User
</div>
</template>
<script setup>
</script>
<!-- scoped css的作用域 -->
<style scoped>
div{
height:50px;
width:50px;
background-color: rgb(255, 127, 168);
margin:5px;
}
</style>
模板内容
- 模板中是一个
div
标签,用于显示用户相关的具体内容,比如用户头像、用户名等。
样式定义
- 样式中设置
div
高度为 50px,宽度为 50px,背景颜色为rgb(255, 127, 168)
,外边距为 5px,用于展示用户信息的样式效果。
数据驱动
在 AppMain 模块下 , 我们添加一个打分的组件
<template>
<main>
Main
<h1>你的评分是{{score}}</h1>
<!-- 父子组件传递数据 -->
<Rate :value="score"/>
<Item/>
<Item/>
</main>
</template>
<script setup>
import Item from './Item.vue'
import Rate from './Rate.vue'
import {ref} from 'vue'
// 创建一个ref , 默认值为3
// 将数据从父组件传递给子组件
const score = ref(3)
</script>
<style scoped>
main {
flex : 1;
height: 500px;
background-color: rgb(136, 111, 137);
}
</style>
Rate
<template>
<div>
{{rate}}
</div>
</template>
<!-- vue 中script setup的作用: -->
<!-- 自动暴露组件的属性和方法。
在 “script setup” 中定义的变量、函数等会自动暴露给模板使用,
无需显式地通过return语句返回。 -->
<script setup>
import {ref,defineProps,computed} from 'vue'
//用于props业务消费数据 , 不是自身的数据 ,而是父组件绑定
//子组件和父组件不一定绑定的 , 哪里要用就往哪里绑定
let props = defineProps({
//限制为Number类型
value : Number
})
//组件自有的数据
let count = ref(0)
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value))
</script>
<style scoped>
</style>
- 从
vue
导入ref
、defineProps
、computed
。使用defineProps
定义value
属性,限制其类型为Number
,这个属性用于接收父组件(如AppMain
)传递过来的评分数据,是组件间通信的重要方式。
巧妙设计评分
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value))
我的思路是 : 用一个长度为五颗星的尺子slice(5,10)置于"★★★★★☆☆☆☆☆"五颗空五角星上 , 之后在"★★★★★☆☆☆☆☆" 上移动 , 移动的距离是 : props.value
而props.value 是父组件 AppMain 传给子组件的值 , 通过 props 属性取出
如上设计完毕 !