Vue组件树 🤔|设计组件从这里开始👈👈👈

367 阅读4分钟

Vue 的核心思想之一就是组件化开发,而组件树(Component Tree)则是 Vue 应用的基础结构。

如下图的页面 , 我们将页面组件化 得到右边的组件树

结合上面的图 , 依葫芦画瓢 , 我们用 组件化的思想 , 设计出下面的页面 :

一个实际的页面,将其组件化后得到了一棵包含多个组件的组件树。比如,一个常见的网页布局包含顶部的导航栏、侧边栏、主体内容区域等部分。

我们可以把这些部分分别抽象成AppHeaderAppAsideAppMain、组件 , 再加上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文件中,我们首先导入了AppAsideAppHeaderAppMain组件,以便在模板中使用它们。

模板布局


  • 模板中使用div元素进行布局,外层的div设置类为contaner,内部AppHeader独占一行,接着是一个类为flxdiv,在这个弹性布局容器中,AppMainAppAside并列排放,并且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导入refdefinePropscomputed。使用defineProps定义value属性,限制其类型为Number,这个属性用于接收父组件(如AppMain)传递过来的评分数据,是组件间通信的重要方式。

巧妙设计评分

let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value))

我的思路是 : 用一个长度为五颗星的尺子slice(5,10)置于"★★★★★☆☆☆☆☆"五颗空五角星上 , 之后在"★★★★★☆☆☆☆☆" 上移动 , 移动的距离是 : props.value

而props.value 是父组件 AppMain 传给子组件的值 , 通过 props 属性取出

如上设计完毕 !