Vue开发实战(03)-组件化开发

news2024/11/23 12:39:12

对组件功能的封装,可以像搭积木一样开发网页。

Vue官方的示例图对组件化开发的形象展示。左边是一个网页,可以按照功能模块抽象成很多组件,这些组件就像积木一样拼接成网页。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aS7Zk8tp-1686298456553)(null)]

1 什么是组件化开发

1.1 浏览器封装好的组件

在页面的源码里写出的button标签,会在前端页面中显示如下样式:

这button就是个组件,这样前端页面在显示上会加上边框和鼠标悬停样式,还可使用click事件触发函数等。只不过这是浏览器封装好的组件,编码只需使用如下代码。

<button> 按钮 </button>

1.2 Vue自定义组件

把一个功能的模板(template)封装在一个.vue文件。如下图,把每个组件的逻辑和样式,即JS和CSS封装在一起,方便在项目中复用整个组件:

项目有导航、侧边栏、表格、弹窗等组件,并且也会引入Element3组件库。也会定制业务相关组件,最终通过这些组件,积木式搭建页面。

Vue组件化机制很好用,只需在其基础上,掌握和学习组件化在使用上的设计理念,以实现高效的代码复用,开发中把组件分成:

  • 通用型组件
  • 业务型组件

通用型组件就是各大组件库的组件风格,包括按钮、表单、弹窗等通用功能。业务型组件包含业务的交互逻辑,包括购物车、登录注册等,和我们不同的业务强绑定。

设计组件的要点,先选择一个简单的组件。

全局组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TodoList</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="app">
    <input type="text" v-model="todoValue"/>
    <button @click="submit">提交</button>
    <ul>
        <!--
            <li v-for="item of list">{{item}}</li>
            -->

        <!-- 这里的 list 代表new Vue.data里的 list -->
        <!-- :就是 v-bind,将值传递给组件 -->
        <todo-item v-for="item of list"
                   :item="item">
        </todo-item>
    </ul>
</div>

<script>
    // 全局组件
    Vue.component('TodoItem', {
        // 通过 :item="item"接收其值
        props: ["item"],
        template: '<li>{{item}}</li>'
    });
    var app = new Vue({
        el: '#app',
        data: {
            list: []
        },
        methods: {
            submit: function () {
                this.list.push(this.todoValue)
                this.todoValue = ''
            }
        }
    })
</script>
</body>
</html>

效果:

局部组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>局部组件</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="app">
    <input type="text" v-model="todoValue"/>
    <button @click="submit">提交</button>
    <ul>
        <todo-item v-for="item of list"
                   :item="item">
        </todo-item>
    </ul>
</div>

<script>
    // 局部组件
    var TodoItem = {
        props: ["item"],
        template: '<li>{{item}}</li>'
    }
    var app = new Vue({
        el: '#app',
        components:{
            TodoItem
        },
        data: {
            list: []
        },
        methods: {
            submit: function () {
                this.list.push(this.todoValue)
                this.todoValue = ''
            }
        }
    })
</script>
</body>
</html>

效果:

2 组件间传值

2.1 父组件 -> 子组件

刚才的全局组件案例,其实就包含父组件向子组件传值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TodoList</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="root">
    <div>
        <input type="text" v-model="todoValue"/>
        <button @click="handleBtnClick">提交</button>
    </div>
    <ul>
<!--        通过 v-bind,将父组件的 item 值传给子组件了-->
        <todo-item :content="item"
                   :index="index"
                   v-for="(item, index) in list"
                   @delete="handleItemDelete">
        </todo-item>
    </ul>
</div>

<script>

    // 定义了一个名为TodoItem的组件
    // new Vue的子组件
    // 在代码中,通过使用</todo-item>标签,用到了该子组件
    var TodoItem = {
        // 该组件接受内容和索引作为属性
        // 并在列表中显示
        props: ['content', 'index'],
        template: "<li @click='handleItemClick'>{{content}}</li>",
        methods: {
            handleItemClick: function () {
                this.$emit("delete", this.index);
            }
        }
    }

    // new Vue属于全局组件
    // 在本 demo 中,也属于最外层的父组件
    // 整个root div 区域也就是该父组件的模板
    // 定义了一个名为app的Vue实例
    var app = new Vue({
        el: "#root",
        components: {
            TodoItem: TodoItem
        },
        // 该实例具有
        data: {
            // 一个todoValue数据属性
            todoValue: "",
            // 一个list数组属性
            list: []
        },
        methods: {
            // 当用户点击提交按钮时
            handleBtnClick: function () {
                // 应用程序将todoValue添加到list数组
                this.list.push(this.todoValue)
                // 并将todoValue重置为空字符串
                this.todoValue = ""
            },
            // 当用户单击列表中的项目时
            // 应用程序将该项目从列表中删除
            handleItemDelete: function (index) {
                this.list.splice(index2, 1)
            }
        }
    })
</script>
</body>
</html>

2.2 子组件 -> 父组件

若现在要实现,点击待办项,能将其删除,就涉及子组件传值给父组件了。

先实现一个click功能:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子组件传值给父组件</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="root">
    <div>
        <input type="text" v-model="todoValue"/>
        <button @click="handleBtnClick">提交</button>
    </div>
    <ul>
        <!-- 通过 v-bind,将父组件的 item 值传给子组件了-->
        <todo-item :content="item"
                   :index="index"
                   v-for="(item, index) in list"
        >
        </todo-item>
    </ul>
</div>

<script>

    // 定义了一个名为TodoItem的组件,new Vue的子组件
    // 在代码中,通过使用</todo-item>标签,用到了该子组件
    var TodoItem = {
        // 该组件接受内容和索引作为属性
        // 并在列表中显示
        props: ['content', 'index'],
        // v-on:click 简写成 @click
        template: "<li @click='handleItemClick'>{{content}}</li>",
        methods: {
            handleItemClick: function () {
                alert("click")
            }
        }
    }

    // new Vue属于全局组件
    // 在本 demo 中,也属于最外层的父组件
    // 整个root div 区域也就是该父组件的模板
    // 定义了一个名为app的Vue实例
    var app = new Vue({
        el: "#root",
        components: {
            TodoItem: TodoItem
        },
        // 该实例具有
        data: {
            // 一个todoValue数据属性
            todoValue: "",
            // 一个list数组属性
            list: []
        },
        methods: {
            // 当用户点击提交按钮时
            handleBtnClick: function () {
                // 应用程序将todoValue添加到list数组
                this.list.push(this.todoValue)
                // 并将todoValue重置为空字符串
                this.todoValue = ""
            }
        }
    })
</script>
</body>
</html>

效果:

现在考虑,把子组件数据传递到父组件,由父组件决定子组件到底显示哪些值。

所以要实现删除,就要将子组件内容传给父组件,父组件来改变数据,父组件的数据变化了,子组件的数据自然就会变更。

在Vue.js中,可以通过在子组件中触发一个自定义事件并传递数据来实现将子组件数据传递到父组件。父组件可以监听子组件的自定义事件,并在事件处理程序中接收传递的数据并更新父组件的数据。这样,父组件的数据变化会自动更新子组件的数据,从而实现删除功能。

父组件的数据变化为啥会自动更新子组件的数据

在Vue.js中,当父组件的数据更新时,它会重新渲染所有子组件。这是因为Vue.js使用了响应式数据绑定的机制,当父组件的数据变化时,所有依赖于该数据的子组件都会自动更新。这个机制是通过Vue.js内部实现的虚拟DOM和数据依赖追踪来实现的。因此,当父组件的数据变化时,子组件的数据也会自动更新,从而实现了数据的同步。

那就来发事件吧:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子组件传值给父组件</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="root">
    <div>
        <input type="text" v-model="todoValue"/>
        <button @click="handleBtnClick">提交</button>
    </div>
    <ul>
        <!-- 通过 v-bind,将父组件的 item 值传给子组件 -->
        <!-- 在父组件里创建子组件的同时,就能监听子组件发出的事件
                一旦子组件被触发了,就会执行父组件的 handleItemDelete -->
        <todo-item :content="item"
                   :index="index"
                   v-for="(item, index) in list"

                   @delete="handleItemDelete"
        >
        </todo-item>
    </ul>
</div>

<script>

    // 定义了一个名为TodoItem的组件,new Vue的子组件
    // 在代码中,通过使用</todo-item>标签,用到了该子组件
    var TodoItem = {
        // 该组件接受内容和索引作为属性
        // 并在列表中显示
        props: ['content', 'index'],
        // v-on:click 简写成 @click
        template: "<li @click='handleItemClick'>{{content}}</li>",
        methods: {
            handleItemClick: function () {
                // alert("JavaEdge 666")
                // 点击子组件时,子组件对外发出事件
                this.$emit("delete")
            }
        }
    }

    // new Vue属于全局组件
    // 在本 demo 中,也属于最外层的父组件
    // 整个root div 区域也就是该父组件的模板
    // 定义了一个名为app的Vue实例
    var app = new Vue({
        el: "#root",
        components: {
            TodoItem: TodoItem
        },
        // 该实例具有
        data: {
            // 一个todoValue数据属性
            todoValue: "",
            // 一个list数组属性
            list: []
        },
        methods: {
            // 当用户点击提交按钮时
            handleBtnClick: function () {
                // 应用程序将todoValue添加到list数组
                this.list.push(this.todoValue)
                // 并将todoValue重置为空字符串
                this.todoValue = ""
            },
            handleItemDelete: function () {
                alert("delete")
            }
        }
    })
</script>
</body>
</html>

效果:

看来发出的事件生效了,那么再小改一处,让父组件把元素清空:

handleItemDelete: function () {
    // alert("delete")
    this.list = [];
}

现在,考虑只删除点击的那一项,而不是清空呢?父组件给子组件传个 index,子组件必须接收它:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子组件传值给父组件</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="root">
    <div>
        <input type="text" v-model="todoValue"/>
        <button @click="handleBtnClick">提交</button>
    </div>
    <ul>
        <!-- 通过 v-bind,将父组件的 item 值传给子组件 -->
        <!-- 在父组件里创建子组件的同时,就能监听子组件发出的事件
                一旦子组件被触发了,就会执行父组件的 handleItemDelete -->
        <todo-item :content="item"
                   :index="index"
                   v-for="(item, index) in list"
                   @delete="handleItemDelete">
        </todo-item>
    </ul>
</div>

<script>

    // 定义了一个名为TodoItem的组件,new Vue的子组件
    // 在代码中,通过使用</todo-item>标签,用到了该子组件
    var TodoItem = {
        // 该组件接受内容和索引作为属性
        // 并在列表中显示
        props: ['content', 'index'],
        // v-on:click 简写成 @click
        template: "<li @click='handleItemClick'>{{content}}</li>",
        methods: {
            handleItemClick: function () {
                // alert("JavaEdge 666")
                // 点击子组件时,子组件对外发出事件
                // this.$emit("delete")
                // 点击子组件时,子组件对外发出事件,还顺带一个参数也发出去,那么监听事件的handleItemDelete就能拿到 index
                this.$emit("delete",this.index)
            }
        }
    }

    // new Vue属于全局组件
    // 在本 demo 中,也属于最外层的父组件
    // 整个root div 区域也就是该父组件的模板
    // 定义了一个名为app的Vue实例
    var app = new Vue({
        el: "#root",
        components: {
            TodoItem: TodoItem
        },
        // 该实例具有
        data: {
            // 一个todoValue数据属性
            todoValue: "",
            // 一个list数组属性
            list: []
        },
        methods: {
            // 当用户点击提交按钮时
            handleBtnClick: function () {
                // 应用程序将todoValue添加到list数组
                this.list.push(this.todoValue)
                // 并将todoValue重置为空字符串
                this.todoValue = ""
            },
            handleItemDelete: function (index) {
                // alert("delete")
                // this.list = [];
                alert(index)
            }
        }
    })
</script>
</body>
</html>

效果:当我点击 index=0 的 java 时,弹窗顺势而出

最终实现删除指定项:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子组件传值给父组件</title>
    <script src="../vue.js"></script>
</head>
<body>

<div id="root">
    <div>
        <input type="text" v-model="todoValue"/>
        <button @click="handleBtnClick">提交</button>
    </div>
    <ul>
        <!-- 通过 v-bind,将父组件的 item 值传给子组件 -->
        <!-- 在父组件里创建子组件的同时,就能监听子组件发出的事件
                一旦子组件被触发了,就会执行父组件的 handleItemDelete -->
        <todo-item :content="item"
                   :index="index"
                   v-for="(item, index) in list"
                   @delete="handleItemDelete">
        </todo-item>
    </ul>
</div>

<script>

    // 定义了一个名为TodoItem的组件,new Vue的子组件
    // 在代码中,通过使用</todo-item>标签,用到了该子组件
    var TodoItem = {
        // 该组件接受内容和索引作为属性
        // 并在列表中显示
        props: ['content', 'index'],
        // v-on:click 简写成 @click
        template: "<li @click='handleItemClick'>{{content}}</li>",
        methods: {
            handleItemClick: function () {
                // alert("JavaEdge 666")
                // 点击子组件时,子组件对外发出事件
                // this.$emit("delete")
                // 点击子组件时,子组件对外发出事件,还顺带一个参数也发出去,那么监听事件的handleItemDelete就能拿到 index
                this.$emit("delete",this.index)
            }
        }
    }

    // new Vue属于全局组件
    // 在本 demo 中,也属于最外层的父组件
    // 整个root div 区域也就是该父组件的模板
    // 定义了一个名为app的Vue实例
    var app = new Vue({
        el: "#root",
        components: {
            TodoItem: TodoItem
        },
        // 该实例具有
        data: {
            // 一个todoValue数据属性
            todoValue: "",
            // 一个list数组属性
            list: []
        },
        methods: {
            // 当用户点击提交按钮时
            handleBtnClick: function () {
                // 应用程序将todoValue添加到list数组
                this.list.push(this.todoValue)
                // 并将todoValue重置为空字符串
                this.todoValue = ""
            },
            handleItemDelete: function (index) {
                // alert("delete")
                // this.list = [];
                // alert(index)
                /**
                 * 这段代码的作用是从列表中删除指定索引的元素:
                 * 1. list是一个列表对象。
                 * 2. splice()是一个JavaScript数组方法,它用于在数组中添加或删除元素
                 *      第一个参数:要删除或添加元素的起始索引
                 *      第二个参数:要删除的元素数量
                 * 3. 因此,这行代码将从list列表中删除指定索引的元素
                 */
                this.list.splice(index, 1)
            }
        }
    })
</script>
</body>
</html>

总结

为精简代码,注意 v-bind:index="index" 可简写成 :index="index"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/628452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lecture 21 Summarisation

目录 Extractive: Single-DocExtractive: Multi-DocAbstractive: Single-DocEvaluationConclusion summarisation Distill the most important information from a text to produce shortened or abridged versionExamples outlines of a documentabstracts of a scientific ar…

MapReduce【小文件的优化-Sequence文件】

在实际开发中&#xff0c;我们肯定希望提高MapReduce的工作效率&#xff0c;其实提高MapReduce的效率&#xff0c;无非就是提高Map阶段和Reduce阶段的效率。 Map阶段优化之小文件问题 我们知道Map阶段中的MapTask个数是与InputSplit的个数有关的&#xff0c;一般一个InputSpl…

《微服务实战》 第二十八章 分布式锁框架-Redisson

前言 Redisson 在基于 NIO 的 Netty 框架上&#xff0c;充分的利⽤了 Redis 键值数据库提供的⼀系列优势&#xff0c;在Java 实⽤⼯具包中常⽤接⼝的基础上&#xff0c;为使⽤者提供了⼀系列具有分布式特性的常⽤⼯具类。使得原本作为协调单机多线程并发程序的⼯具包获得了协调…

VR全景营销颠覆传统营销模式,让商企博“出圈”

在激烈的市场竞争中&#xff0c;营销成为了商企博“出圈”的重要课题&#xff0c;随着5G的到来&#xff0c;VR全景迈入了快速发展时期&#xff0c;随着VR全景的普及应用&#xff0c;商业领域也逐渐引入了VR全景营销。 时下&#xff0c;商企的营销是越发困难&#xff0c;传统的营…

币圈下半年重点之一:以太坊坎昆升级,将带来哪些实质性利好?

近期BRC-20大火&#xff0c;主打价值存储的比特币竟然生态比以太坊还热&#xff0c;但要论生态&#xff0c;以太坊才是真正的王者&#xff0c;因为其正在悄悄酝酿下一个重大升级——坎昆&#xff08;Dencun&#xff09;升级。 最新消息&#xff0c;以太坊开发者已经就Dencun升级…

【MySQL高级篇笔记-数据库的设计规范(中) 】

此笔记为尚硅谷MySQL高级篇部分内容 目录 一、为什么要数据库设计 二、范式 1、范式简介 2、范式都包括哪些 3、键和相关属性的概念 4、第一范式(1st NF) 5、第二范式(2nd NF) 6、第三范式(3rd NF) 7、小结 三、反范式化 1、概述 2、 应用举例 3、反范式的新问…

逆向分析高薪就业:学习Android逆向开发,拥抱行业机会!

简述 Android 逆向开发是指利用各种技术手段对安卓应用程序进行逆向分析和研究&#xff0c;以了解应用程序的内部机制&#xff0c;发现应用程序中的漏洞、脆弱性或者安全问题&#xff0c;并提供相关的解决方案。逆向开发技术可以帮助开发人员更好地了解应用程序的构成、运行机…

Django实现接口自动化平台(六)httprunner(2.x)基本使用【持续更新中】

上一章&#xff1a; Django实现接口自动化平台&#xff08;五&#xff09;httprunner&#xff08;2.x&#xff09;基本使用【持续更新中】_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、 api 文件夹&#xff08;没有任何数据依赖的场景&#xff09; api 文件夹&…

一键生成代码

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

(五)CSharp-进一步理解接口

一、什么是接口 接口是指定一组函数成员而不实现它们的引用类型。 实现接口&#xff1a; 只能由类和结构来实现接口。 二、声明接口 接口声明不能包含以下成员&#xff1a; 数据成员静态成员 接口声明只能包含如下类型的非静态成员函数的声明&#xff1a; 方法属性事件索…

25张python代码速查表,让你python能力突飞猛进的秘诀!

在学习函数时&#xff0c;总是会有很多东西学得很快&#xff0c;遗忘得也很快。但其实在学习中&#xff0c;只需要知道相关参数&#xff0c;加以调整就够了。所以你可能需要这本秘籍&#xff01; 即整理了Python科学速查表&#xff0c;就可以帮你解决以上的问题。当你在练习的时…

怎样正确做 Web 应用的压力测试?字节8年测试5个步骤给我看师了

Web应用&#xff0c;通俗来讲就是一个网站&#xff0c;主要依托于浏览器来访问其功能。 那怎么正确做网站的压力测试呢&#xff1f; 提到压力测试&#xff0c;我们想到的是服务端压力测试&#xff0c;其实这是片面的&#xff0c;完整的压力测试包含服务端压力测试和前端压力测…

高可用系统架构总结

文章目录 系统设计的一些原则海恩法则墨菲定律 软件架构中的高可用设计什么是高可用故障的度量与考核解决高可用问题具体方案 集群化部署负载均衡负载均衡实现内部服务外部服务数据库 负载均衡算法round-robinip_hashhash key 失败重试健康检查TCPHTTP 隔离线程隔离进程隔离集群…

华秋观察 | 通讯产品 PCB 面临的挑战,一文告诉你

印制电路板是电子产品的关键电子互联件&#xff0c;被誉为“电子产品之母”。随着电子产品相关技术应用更快发展、迭代、融合&#xff0c;PCB作为承载电子元器件并连接电路的桥梁&#xff0c;为满足电子信息领域的新技术、新应用的需求&#xff0c;行业将迎来巨大的挑战和发展机…

rocky9脚本py格式

在linux7上编写/root/CreateFile.py的python3脚本&#xff0c;创建20个文件/root/test/File01至/root/test/File20&#xff0c;如果文件存在&#xff0c;则先删除再创建&#xff1b;每个文件的内容同文件名&#xff0c;如File01文件的内容为”File01” 先在root目录下建立所需…

使用单片机遇到的几个问题及解决方案1

1.为什么我跟着视频学习的过程中&#xff0c;我没有找到“端口"的选项呢&#xff1f;我甚至没有出现“其他插口”。 想要找到设备管理器最快的方法就是&#xff1a; 首先如果把输入法调为大写形式&#xff0c;然后按下“WINX”&#xff0c;再按“M”就会出现一个设备管理…

python制作炸弹人游戏,一起来爆破消灭敌人吧

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 《炸弹人》是HUDSON出品的一款ACT类型游戏&#xff0c;经典的第一作登陆在FC版本&#xff0c;游戏于1983年发行。 游戏具体操作是一个机器人放置炸弹来炸死敌人&#xff0c;但也可以炸死自己&#xff0c;还有些增强威力…

K8S之服务Service(十三)

1、Service概念&#xff1a; Kubernetes中的 Pod是有生命周期的&#xff0c;它们可以被创建&#xff0c;也可以被销毁&#xff0c;然而一旦被销毁pod生命就永远结束&#xff0c;这个pod就不存在了&#xff0c;通过ReplicaSets能够动态地创建和销毁Pod&#xff08;例如&#xff…

【计算思维题】少儿编程 蓝桥杯青少组计算思维 数学逻辑思维真题详细解析第8套

少儿编程 蓝桥杯青少组计算思维题真题及解析第8套 1、下列哪个选项填到填到下图空缺处最合适 A、 B、 C、 D、 答案:D 考点分析:主要考查小朋友们的观察能力,从给定的图中可以看到,图中的线条都是有实现和虚

【C++ 学习 ⑨】- 万字详解 string 类(上)

目录 一、为什么学习 string 类&#xff1f; 二、标准库中的 string 类 三、C STL容器是什么&#xff1f; 四、string 类的成员函数 4.1 - 构造函数 4.2 - 赋值运算符重载 4.3 - 容量操作 4.4 - 遍历及访问操作 4.4.1 - operator[] 和 at 4.4.2 - 迭代器 4.5 - 修改…