vue的组件化开发?一个小demo就带你掌握!
什么是组件化思想
组件化思想来源于软件工程中的模块化和封装原则,让开发者能够将复杂的用户界面分解细化成一块块可复用的、独立的组件。每个组件负责一块功能,组件之间相互独立,并通过特定方式进行沟通联系,从而实现高内聚、低耦合。
demo需求
在同一个页面中,点击不同按钮展示不同的信息:当我点击“购物车”,下方展示我的购物清单;当我点击“todos”,下方展示我的待办事项。
分析可知整个项目应该拆解成三个模块:导航头、购物车信息和todos信息。考虑到代码的优雅性和复用性,我们应该将购物车信息和todos信息分别写成两个组件,而导航头的两个按钮始终在该页面上显示并为这两个组件共用,所以两个按钮就放在在根组件上。
代码实现
(本文案例只为展现组件化的使用方法,在实际应用中应当考虑模块的复用性和项目的可维护性,酌情组件化)
项目目录
components中写入购物车和todos的vue文件,App.vue为根组件
组件引入
① Shopping.vue和Todos.vue两个子组件暂时先简写成下面的形式以表明是两个不同子组件,详细代码内容先省略
<!-- Shopping.vue中 -->
<template>
<div>shopping</div>
</template>
<!-- Todos.vue中 -->
<template>
<div>todos</div>
</template>
② 在根组件App.vue中引入和使用Shopping.vue和Todos.vue两个文件:
import Shopping from './components/Shopping.vue'
从指定路径导入Shopping.vue子组件,并定义为一个变量名Shopping;
import Todos from './components/Todos.vue
同理;
并在HTML结构中使用两个组件标签<Shopping>
和 <Todos>
,它们将被替换为对应的组件实例。
<template>
<div class="app">
<button class="btn">购物车</button>
<button class="btn">todos</button>
<Shopping></Shopping>
<Todos></Todos>
</div>
</template>
<script setup>
import Shopping from './components/Shopping.vue' // 引入组件
import Todos from './components/Todos.vue'
</script>
<style lang="css" scoped>
.app {
text-align: center;
}
.btn {
font-size: 20px;
width: 100px;
height: 40px;
margin: 20px;
border: 1px solid pink;
}
</style>
此时效果如下:
由于使用了
<script setup>
,这两个组件会自动在模板中局部注册,无需再显式调用defineComponent
或者使用export default
。这意味着在模板中可以直接使用<Shopping>
和<Todos>
标签,而无需任何额外的注册步骤。
组件切换
两个组件切换显示,即浏览器分时渲染这两个组件:为两个按钮都绑定点击事件,点击按钮时都触发同一个函数,但传参不同,以此来对应不同组件在界面上的显示。
<template>
<div class="app">
<button class="btn" @click="changeTab(1)">购物车</button>
<button class="btn" @click="changeTab(2)">todos</button>
<Shopping v-if="tabIndex === 1"></Shopping>
<Todos v-else></Todos>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Shopping from './components/Shopping.vue' // 引入组件
import Todos from './components/Todos.vue'
let tabIndex = ref(1)
const changeTab = (index) => {
console.log(index);
tabIndex.value = index
}
</script>
此时效果如下:
两个子组件具体代码
Shopping.vue
<template>
<div class="shopping">
<table>
<thead>
<th>序号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</thead>
<tbody>
<tr v-for="(book,index) in books">
<td>{{ index + 1 }}</td>
<td>{{ book.name }}</td>
<td>{{ book.date }}</td>
<td>{{ book.price }}</td>
<td>{{ book.count }}</td>
<td>
<button :disabled="book.count <= 0" @click="decrementCount(index)">-</button>
<span class="counter">{{ book.count }}</span>
<button @click="addCount(index)">+</button>
</td>
</tr>
</tbody>
</table>
<h3>总价格:{{ totalPrice }}</h3>
</div>
</template>
<script setup>
import { reactive,computed } from 'vue';
const books = reactive([
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《编程珠玑》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代码大全》',
date: '2006-3',
price: 128.00,
count: 1
},
]
)
const totalPrice = computed(() => {
let total = 0
books.forEach(item => {
total += item.price * item.count
})
return total;
})
const addCount = (index) => {
// console.log(index);
books[index].count++ // 数组是响应式的,变更了数组内容就会重新渲染
}
const decrementCount = (index) => {
// if(books[index].count >= 1)
books[index].count--;
}
</script>
<style lang="css" scoped>
.shopping {
}
table {
margin: 0 auto;
border: 1px solid pink;
border-collapse: collapse;
border-spacing: 0;
}
th,td {
padding: 8px 16px;
border: 1px solid pink;
}
.counter {
margin: 0 5px;
}
</style>
Todos.vue
<template>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input type="text" class="new-todo" placeholder="想做的事" @keyup.enter="addTodo">
</header>
<section class="main">
<input type="checkbox" class="toggle-all">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<li class="todo" v-for="todo in state.todos">
<div class="view">
<input type="checkbox" class="toggle" v-model="todo.completed">
<label>{{todo.title}}</label>
<button class="destroy"></button>
</div>
</li>
</ul>
</section>
</section>
</template>
<script setup>
import { reactive } from 'vue'
const state = reactive({
todos: [
{id: 1, title: '吃饭', completed: false},
{id: 2, title: '睡觉', completed: true},
{id: 3, title: '打豆豆', completed: false}
]
})
</script>
<style lang="css" scoped>
</style>
总结
在 Vue 中,一个组件通常包含以下部分:
- 模板(Template) :定义了组件的 HTML 结构,可以使用 Vue 的模板语法来绑定数据和事件。
- 脚本(Script) :包含了组件的业务逻辑,包括数据、方法、计算属性、监听器等。
- 样式(Styles) :组件的 CSS 样式,可以是普通的 CSS 或者是作用域受限的 scoped styles。
任何应用都可以被拆分成一棵组件树,便于代码组织和扩展。
转载自:https://juejin.cn/post/7394369246242111515