五分钟带你摸透 Vue组件及组件通讯

简介: 五分钟带你摸透 Vue组件及组件通讯

一.组件化开发

  • 组件 (Component) 是 Vue.js 强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代 码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。
  • 在vue中都是组件化开发的,组件化开发就是把一个完整的页面分割成一个一个的小组件
  • 组件化开发 容易维护 可以复用


1.1.定义简单的组件

1.1.1语法:

Vue.component()里面有两个参数:

  1. 组件名称
  2. 是个对象 对组件的设置 包括html模板 数据侦听器等
 Vue.component('first-component',{  
       template:'<h1>我爱我的祖国</h1>'
  })


1.1.2组件的使用:
<div id="app">   
 <first-component></first-component> 
</div>

组件不能写到#app的元素外面


1.1.3组件的重复使用

组件就是一个可以重复引用的Vue实例 可以在页面中引用多次

<div id="app">    
<first-component></first-component>    
<first-component></first-component>    
<first-component></first-component>    
<first-component></first-component>    
<first-component></first-component> 
</div>


1.1.4定义的组件只能有一个根元素

案例:

下面定义组件中两个h1都输入根元素

Vue.component('aa',{
template:'<h1>爱我中华</h1><h1>建设我们的国家</h1>'
})


可以改写成如下:

Vue.component('aa',{
template:'
<div>
    <h1>爱我中华</h1>
    <h1>建设我们的国家</h1>
</div>
'
})


1.2.组件中的事件

组件就是可以重复使用的Vue实例 所以组件中也有Vue中的事件

data computed watch methods 以及生命周期钩子函数等 但是组件中没有el

组件中也可以为元素添加事件:

        Vue.component('aa', {
            template: `
                <div class="bottom">
                <button @click="turnOn">我是测试按钮</button>
                </div>
                `,
            methods: {
                turnOn(){
                    console.log('我是组件中的事件')
                }
            }
        })


1.3.组件中的数据

组件中的data数据 与new Vue中的不同 为了保证组件中的数据是私有的所以组件中的data数据是一个返回函数 组件中的数据都在函数的作用域中 保证组件中的数据互不感染

 data() {
      return {
          msg: '爱我中华'
       }
    }


二.组件通讯

因为组件对封闭的 但是在实际的开发中 组件之间的数据是相互依赖 需要相互传递的 具体来说组件通讯分为三大类:

  • 父组件为子组件传递数据
  • 子组件为父组件传递数据
  • 非父子组件之间传递数据


2.1 父传子

父组件向子组件传递数据

  • 在子组件中定义props属性 值为数组类似于data 但data中的数据来自本身 而props中的数据来自父组件
  • 子组件使用模板中使用props中的属性和data中的用法相同
  • 父组件通过props传值给子组件

    输出结果为:

    说明:
  1. 创建Vue实例 data中的数据msg为一个数组
  2. 创建组件 在整个项目中 2组件相对就是1的子组件
  3. 通过3方式前者msg为props值中的数据 后者msg为newVue中data中的数据
  4. 最后正是props中的属性也有data中的使用方法 将数据进行遍历在页面中
    **注意:props负责获取父组件的传递过来的,props中的值是只读的,不允许修改 **


2.2 子传父

原理

  • 父组件使用子组件时 在其中定义一个自定义事件 并且绑定父组件中的一个自定义函数 当事件被调用时执行自定义函数
  • 子组件通过this$emit执行自定义事件

    最终输出结果为3
  1. 在子组件中定义一个点击事件 触发时执行子组件中的dian函数 并且将参数传入函数中
  2. 在上面的函数中通过this.$emit(‘事件名称’,参数)调用3中的a自定义事件并且将参数传过去
  3. 当a事件被触发时 会执行4中的aaa自定义函数 同时获取参数 最终实现子组件向父组件传数据


实例改造

根据父子组件之间的数据传递实现产品列表的组件化开发

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 1000px;
            margin: 100px auto;
            text-align: center;
        }
        table {
            width: 900px;
            margin: 50px auto;
            border-collapse: collapse;
        }
        table,
        th,
        td {
            border: 1px solid rgb(218, 124, 17);
        }
        .color {
            background-color: rgb(26, 172, 152);
        }
    </style>
</head>
<body>
    <div id="app">
        <atitle @tian="tian" :aatitle="aupda" @cha="cha"></atitle>
        <acontent :content="newcontent" @del="del" @upda="upda"></acontent>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        Vue.component('atitle', {
            props: ['aatitle'],
            data() {
                return {
                    keyword: ''
                }
            },
            template: `<div>
                型号 <input type="text" v-model=aatitle.name>
                价格 <input type="text" v-model=aatitle.may @keyup.enter="tian">
                <button @click="tian">录入</button><br>
                <input type="text" v-model="keyword">
            </div>`,
            methods: {
                tian() {
                    this.$emit('tian', this.aatitle.name, this.aatitle.may)
                    this.aatitle.name = ''
                    this.aatitle.may = ''
                }
            },
            watch: {
                keyword: {
                    handler(newvalue) {
                        this.$emit('cha', newvalue)
                    },
                    immediate: true
                }
            }
        })
        Vue.component('acontent', {
            props: ['content'],
            template: `<table>
                    <tr>
                        <th>编号</th>
                        <th>机型</th>
                        <th>价格</th>
                        <th>时间</th>
                        <th>操作</th>
                    </tr>
                    <tr v-show="this.content.length==0">
                        <td colspan="5">没有任何发布任何产品</td>
                    </tr>
                    <tr v-for="(item,index) in content">
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.may}}</td>
                        <td>{{item.time}}</td>
                        <td>
                            <a href="#"" @click.prevent="del(item.id)">删除</a>
                            <a href="#"" @click.prevent='upda(item.id)'>编辑</a>
                        </td>
                    </tr>
                </table>`,
            methods: {
                del(id) {
                    this.$emit('del', id)
                },
                upda(id) {
                    this.$emit('upda', id)
                }
            }
        })
        const app = new Vue({
            el: '#app',
            data: {
                newcontent: [],
                aupda: {},
                isup: false,
                upid: '',
                content: [{
                        id: 1,
                        name: '华为',
                        may: 5000,
                        time: Date.now()
                    },
                    {
                        id: 2,
                        name: '小米',
                        may: 6000,
                        time: Date.now()
                    },
                    {
                        id: 3,
                        name: '苹果',
                        may: 4500,
                        time: Date.now()
                    },
                    {
                        id: 4,
                        name: '1+',
                        may: 3000,
                        time: Date.now()
                    },
                    {
                        id: 5,
                        name: 'oppo',
                        may: 2000,
                        time: Date.now()
                    },
                    {
                        id: 6,
                        name: '1+2',
                        may: 8000,
                        time: Date.now()
                    },
                    {
                        id: 7,
                        name: '1+3',
                        may: 12000,
                        time: Date.now()
                    }
                ]
            },
            methods: {
                del(id) {
                    let index = this.content.findIndex(item => {
                        return item.id == id
                    })
                    this.content.splice(index, 1)
                    this.newcontent.splice(index, 1)
                },
                tian(name, may) {
                    if (this.isup) {
                        let a = this.content.find(item => {
                            return item.id == this.upid
                        })
                        a.name = name
                        a.may = may
                    } else {
                        let id = this.content.length - 1 < 0 ? 1 : this.content[this.content.length - 1].id + 1
                        let content = {
                            id: id,
                            name: name,
                            may: may,
                            time: Date.now()
                        }
                        this.content.push(content)
                        this.newcontent.push(content)
                    }
                },
                cha(value) {
                    this.newcontent = this.content.filter(item => {
                        return item.name.includes(value)
                    })
                },
                upda(id) {
                    let a = this.content.find(item => {
                        return item.id == id
                    })
                    this.aupda = {
                        name: a.name,
                        may: a.may
                    }
                    this.isup = true
                    this.upid = id
                }
            }
        })
    </script>
</body>
</html>


2.3 非父子之间的组件通讯

原理:

通过一个空的Vue实例来传递数据

const bus =new Vue()

核心逻辑:

组件A给组件B传值:

  1. 组件A给bus注册一个事件,监听事件的处理程序
  2. 组件B触发bus上对应的事件,把 值当成参数来传递
  3. 组件A通过事件处理程序获取数据


最终点击h2控制台会输出2

  1. 创建1和2两个非父子组件以及3空vue实例bus
  2. 在1组件中 钩子函数created中通过bus.$on为bus自定义一个事件aa
  3. 在2组件中 当点击h2元素时触发dian函数 并且将值出过去
  4. 在2组件的dian函数中通过bus.$emit方触发1中的aa事件 并传参过去
  5. 当1中的aa事件被触发时会执行其中的函数并获取参数


实例:

通过非父子组件 实现开关灯案例

  1. 关闭状态:

    开启状态:

    代码如下
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #app {
            width: 500px;
            height: 500px;
            margin: 100px auto;
        }
        .box {
            height: 200px;
            width: 200px;
            margin: 0 auto;
            background-color: black;
            border-radius: 50%;
        }
        .below {
            height: 200px;
            width: 400px;
            margin: 50px auto;
        }
        button {
            margin-left: 66px;
            width: 100px;
            height: 40px;
        }
        .on {
            background-color: rgb(160, 184, 25);
        }
    </style>
</head>
<body>
    <div id="app">
        <zss></zss>
        <sgy></sgy>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        const bus = new Vue()
        Vue.component('zss', {
            data() {
                return {
                    attribute: "on",
                    state: false
                }
            },
            created() {
                bus.$on('lamp', result => {
                    this.state = result
                })
            },
            template: `<div class="box" :class="state?attribute:''"></div>`
        })
        Vue.component('sgy', {
            template: `<div class="below">
                        <button @click="on">开灯</button>
                        <button @click="off">关闭</button>
                      </div>`,
            methods: {
                on() {
                    bus.$emit('lamp', true)
                },
                off() {
                    bus.$emit('lamp', false)
                }
            }
        })
        const app = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>
</html>



相关文章
|
26天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
22天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
2天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
22天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
28 8
|
22天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1059 0
|
28天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
29天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
35 1
vue学习第一章
|
29天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
29天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
下一篇
DataWorks