给小白介绍vue组件化开发

前言

Vue是一种单页应用,在 Vue 单页应用中,通常整个应用只有一个主页面(HTML 文件),通过 JavaScript 在不同的视图之间进行动态切换,而无需每次切换都重新加载整个页面。即事实上一个页面就是一段js代码片段,让这段代码片段挂载到index.html并生效。

组件化开发是一种将软件系统拆分成独立的可复用的组件的开发方式。

就像我们在平常的页面开发中,常常碰到一些例如导航栏部分每个页面都一样不需要动,但是下面有几个模块不一样需要切换,我们可以称之为这是两个组件(我的关注、推荐),事实上这两个组件就是两份代码,我们点击我的关注,我的关注这份代码就生效,点击推荐,另一份就生效。

组件化开发实战应用

效果

购物车组件

js 复制代码
<template>
  <div class="app">
    <button class="btn" @click="changeTab(1)">购物车</button>
    <button class="btn" @click="changeTab(2)">todos</button>

    <!-- shopping -->
    <Shopping v-if="tabIndex === 1"></Shopping>

    <!-- todos -->
    <Todos v-else></Todos>

  </div>


</template>

<script setup>
import Shopping from "./components/Shopping.vue";
import Todos from "./components/Todos.vue";
import { ref } from "vue";

let tabIndex = ref(1)
const changeTab = (index) => {
  // console.log(index);
  tabIndex.value = index
}

</script>

<style lang="css" scoped>
.app {
  text-align: center;
}

.btn {
  font-size: 20px;
  width: 100px;
  height: 40px;
  margin: 20px;
}
</style>

在App.vue中创建两个按钮并绑定两个点击事件@click,在这里我们取名为changeTab并添加了实参,目的就是打标记,当标记为1时购物车生效,标记为2时todos生效

js 复制代码
const changeTab = (index) => {
  // console.log(index);
  tabIndex.value = index
}

注意:将标记tabIndex做成响应式数据(ref),当响应式数据更新,页面也会重新加载

为两个按钮添加一些简单的样式

css 复制代码
.app {
  text-align: center;
}

.btn {
  font-size: 20px;
  width: 100px;
  height: 40px;
  margin: 20px;
}

接下来创建组件(Shopping.vue),在App.vue中声明一个Shopping组件,todos类似。

js 复制代码
import Shopping from "./components/Shopping.vue";
import Todos from "./components/Todos.vue";

声明完成便可以使用了

js 复制代码
    <!-- shopping -->
    <Shopping v-if="tabIndex === 1"></Shopping>

    <!-- todos -->
    <Todos v-else></Todos>

vue中直接对标签做判断v-if,判断标记的值是1/2,是1则购物车标签生效否则todos生效。

创建Shopping.vue

js 复制代码
<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 @click="minusCount(index)" v-bind:disabled="book.count <= 0">-</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
        // console.log(total, item.price);
    })
    return total
})
const addCount = (index) => {
    // console.log(index);
    books[index].count++
}
const minusCount = (index) => {
    books[index].count--
}
</script>
<style lang="css" scoped>
table {
    margin: 0 auto;
    border: 1px solid #e9e9e9;
    border-collapse: collapse;
    border-spacing: 0;
}

th,
td {
    padding: 8px 16px;
    border: 1px solid #e9e9e9;
}

.counter {
    margin: 0 5px;
}
</style>
  • 注意语义化标签,thead、tbody
  • tr中应该是数据库中有多少条数据,就展示多少个tr,因此不能写死。在这里我们创建一个响应式数据books,是一个数组,数组里有多个对象,每个对象就是一条数据。用这个响应式books来模拟数据库数据
js 复制代码
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
    },
])
  • 在tbody中数据不能写死,因此我们通过v-for对books数组做遍历,拿到每一个book对象和下标
  • 两个花括号挖坑,把对象中对应的属性值丢进去即可
  • 两个加减按钮是操作书籍的数量按钮,因此首先绑定两个点击事件,注意我们只需要把实参index丢进去,即可分辨页面上是哪一个加号/哪一个减号
js 复制代码
<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 @click="minusCount(index)" v-bind:disabled="book.count <= 0">-</button>
                        <span class="counter">{{ book.count }}</span>
                        <button @click="addCount(index)">+</button>
                    </td>
                </tr>
            </tbody>
  • 通过index识别到位置后直接进行操作
js 复制代码
const addCount = (index) => {
    // console.log(index);
    books[index].count++
}
const minusCount = (index) => {
    books[index].count--
}
  • 但是需要注意的是,当减号减到0,就不能再减了,因此我们需要对标签添加disabled属性,值为true则禁用,但是我们不能写死,当我们需要动态的操作标签上的某个属性,则可以通过v-bind:对属性进行绑定,添加条件:当book.count小于等于0时。
  • 在最后的总价格中设计到了计算,因此我们使用computed(()=>{})接收一个函数,并返回一个值。计算每一项的单价乘以数量然后累加起来。
js 复制代码
const totalPrice = computed(() => {
    let total = 0
    books.forEach(item => {
        total += item.price * item.count
        // console.log(total, item.price);
    })
    return total
})

todos组件

创建Todos.vue

js 复制代码
<template>
    <section class="todoapp">
        <header class="header">
            <h1>todos</h1>
            <input type="text" class="new-todo" placeholder="想做的事情:" @keydown.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, index) 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 { ref, reactive } from 'vue'
const state = reactive({
    todos: [
        { id: 1, title: '学习', completed: false },
        { id: 2, title: '吃饭', completed: false },
        { id: 3, title: '睡觉', completed: false },
        { id: 4, title: '打豆豆', completed: true },
    ]
})
// 1. 输入new todo 能增加列表
const addTodo = () => {
    console.log();
}
// 2. 手动完成某件事想
// 3. 手动移除某件事
// 4. 点击全选/全不选
</script>

<style lang="css" scoped></style>
  • 这里用到了已经封装好的样式,省的我们再去写css了,如果有需要,查看npm | Home (npmjs.com)
bash 复制代码
npm i todomvc-app-css
  • 下载之后做声明,我们直接在全局的main.js中添加,接下来只需要按照他写好的类名去写就能完成样式了。
js 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import 'todomvc-app-css/index.css'
createApp(App).mount('#app')
  • 注意语义化标签,headersection
  • 在这个组件中每一个li的原理和购物车中类似,不做赘述
  • 用v-model实现数据的双向绑定,当一方变更,另一方也会变更。
js 复制代码
<input type="checkbox" class="toggle" v-model="todo.completed">
  • 这里我们用来响应这个li的状态是否是完成状态。

介绍到这里,这两个组件的开发就基本结束了,但是在todos这个组件中,还剩余一些小功能没实现。

  1. 输入new todo 能增加列表
  2. 点击,手动完成某件事项
  3. 手动移除某件事
  4. 点击全选/全不选

小结

Vue 组件化开发思想是将一个大型应用拆分成多个相对独立且可复用的组件,每个组件都有自己特定的功能和视图。学习完本文,你应该能理解组件化开发有以下特点:

  1. 独立性:组件自身的功能和逻辑相对独立,不依赖于其他组件的内部实现细节。
  2. 可重用性:可以在不同的场景和项目中重复使用已有的组件,大大提高开发效率。
  3. 封装性:将相关的代码、数据和视图封装在组件内部,对外提供清晰的接口。
  4. 可维护性:当需要修改或扩展功能时,只需针对特定组件进行操作,不会影响其他组件。
  5. 组合性:通过不同组件的组合和嵌套,可以灵活构建各种复杂的界面结构。
  6. 测试方便:由于组件的独立性,对其进行单独测试较为容易。
  7. 关注点分离:将视图展示、业务逻辑和数据管理等不同方面的内容分别放在组件的不同部分,便于管理和理解。
  8. 高效开发:减少代码冗余,提高代码的质量和可扩展性。
相关推荐
darling3317 分钟前
vue+elementUI 表单项赋值后无法修改的问题
前端·javascript·vue.js·elementui·ecmascript
呆呆小雅36 分钟前
四、Vue 条件语句
前端·javascript·vue.js
LUwantAC1 小时前
一篇文章学会HTML
前端·javascript·html
小林爱1 小时前
【Compose multiplatform教程12】【组件】Box组件
前端·kotlin·android studio·框架·compose·多平台
山沟沟里的娃1 小时前
pinia从0到1
vue.js
风清云淡_A1 小时前
【再学javascript算法之美】前端面试频率比较高的基础算法题
前端·javascript
xcLeigh1 小时前
HTML5实现喜庆的新年快乐网页源码
前端·html·html5
DT——1 小时前
HTTPS验证流程
前端·https
Tirzano2 小时前
vue3 ts 动态表单原理
前端·javascript·vue.js
m0_748240252 小时前
vue3 前端实现pdf打印预览 printjs
前端·pdf·状态模式