• Vue组件通信(传值)


    先介绍一下什么是组件把:
    创建组件的两种方式:

    • 全局组件
    
    // 组件就是vue的一个拓展实例
     let component=Vue.extend({
         data(){
           return{
             //与vue实例中的data不同,子组件的data必须是一个方法,必须有返回值,且返回值是对象。
             //这样做可以使组件中的数据独立。
             //需要共享数据时可把return的对象声明全局变量
           }
         }
         template:'<div></div>'// 模板  这个组件的html元素
     	// })
        //注册组件
     Vue.component('hehe',component)
    
    

    (简写)

    
     Vue.component('组件名',{
     		template:''// 模板  
     	})
    
    
    • 局部组件
    
    new Vue({
     		el:'#app',
     		data:{
     			test:11
     		},
     		components:{
     			one:{
    		    	template:'<h1>这里是局部组件 </h1>'
    		    }
     		}
    
     	})
    
    

    需要注意的是子组件的命名无法识别驼峰命名法,当组件做为标签使用的时候需要用“-”和小写字母替换该大写字母。

    
    <div>
       <one-data></one-data>
    </div>
    new Vue({
     		el:'#app',
     		data:{
     			test:11
     		},
     		components:{
     			oneData:{
    		    	template:'<h1>这里是局部组件 </h1>'
    		    }
     		}
    
     	})
    
    

    1、父子属性传值
    子组件不能直接使用父级data的内容,也不能直接修改父组件传递的值,但可以通过设置props属性来获得自身属性值。
    原理:

    • 通过子组件的props抛出一个组件标签属性
    • 父组件通过该标签属性将参数传递给子组件
    • 子组件内部通过该标签属性获取值

    代码实现:(实现过程中踩过的坑)
    1.template标签内必须有且只有一个根元素
    2.子组件标签内要通过v-bind的方式绑定父级的data的值
    3.子组件通过props定义的自身属性值(test)获取父组件的data中的内容(父组件:{{name}} ;子组件:{{test}})

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="base/vue.js"></script>
    </head>
    <body>
       <div>
           {{name}}
           <son :test='name'></son>
       </div> 
       <!--实现功能较复杂时,会单独写个template标签,通过id与子组件中的template相关联,否则字符串拼接会很麻烦-->
       <template>
           <div>{{test}}</div>
       </template>
    </body>
    <script>
        new Vue({
            el:'#myApp',
            data:{
                name:'加油鸭!'
            },
            components:{
                son:{
                    template:'#tp',//类似于 el
                    props:['test']
                }
            }
        })
    </script>
    </html>
    
    
    • 再用全局组件写一个父子属性传值,实现点击父组件按钮,子组件div显示和隐藏

    (全局组件无固定父子关系,该组件标签放在哪个标签内就是哪个标签的子组件)

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>父向子传值</title>
        <script src="base/vue.js"></script>
    </head>
    <body>
       <div>
       <!--c1就是myApp的子组件-->
           <c1></c1>
       </div> 
       <template>
           <div>
               <h4>我是c1,是父级</h4>
               <button @click="change">点我c2变</button>
               {{state}}
               <hr>
               <!--写在c1的template内,就是c1的子组件-->
               <c2 :changed='state'></c2>
           </div>
       </template>
       <template>
           <div>
               我是c2,是子级
               <div v-show='changed'><h1>我是div</h1></div>
            </div>
       </template>
    </body>
    <script>
        Vue.component("c1",{
            template:'#tp1',
            data(){
                return {
                    state:true
                }
            },
            methods:{
                change(){
                    this.state=!this.state
                }
            }
        })
        Vue.component("c2",{
            template:'#tp2',
            props:['changed']
        })
        let vm=new Vue({
            el:'#myApp'
        })
    </script>
    </html>
    
    

    2、子父事件传值
    子组件不能直接修改父组件传递的值,可间接通过事件修改

    原理

    • 子组件创建自定义事件
    • 自定义事件的处理函数是父组件的函数
    • 子组件通过$emit触发属于自己的自定义事件

    代码实现:(点击子组件按钮,父组件div显示和隐藏)
    代码中有一些思路注释:

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>子向父传值</title>
        <script src="base/vue.js"></script>
    </head>
    <body>
       <div>
           <c1></c1>
       </div> 
       <template>
           <div>
               <h4>我是c1,是父级</h4>
               <div v-show='state'><h1>我是div</h1></div>           
               <hr>
               <!--c2自定义了一个changed事件处理父组件的函数change-->
               <c2 @changed='change'></c2>
           </div>
       </template>
       <template>
           <div>
               我是c2,是子级
               <!--子组件点击按钮,父组件显示隐藏,当然有点击事件啦,
               所以给button加点击事件触发一个函数,发现c2没有设置methods,
               所以去c2的实例中加一个methods并设置函数sclick,
               再通过sclick函数把其自定义事件changed抛出,
               changed里面就是c1的处理函数-->
               <button @click="sclick">点我c1变</button>
            </div>
       </template>
    </body>
    <script>
        Vue.component("c1",{
            template:'#tp1',
            data(){
                return {
                    state:true
                }
            },
            methods:{
                change(){
                    this.state=!this.state
                }       
            }
           
        })
        Vue.component("c2",{
            template:'#tp2',
            methods:{
                sclick(){
                    this.$emit('changed')
                }
            }
        })
        let vm=new Vue({
            el:'#myApp'
        })
    </script>
    </html>
    
    

    3、非父子传值

    原理

    • 创建公共汽车实例
    • 实例上注册事件,事件的处理函数就是要改变数据的处理函数
    • 触发事件

    (1)公有的父元素作为桥接-----结合父子属性传值和子父事件传值来实现(适用于亲兄弟)

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>兄弟传值</title>
        <script src="base/vue.js"></script>
    </head>
    <body>
       <div>
           我是父级
           {{state}}
           <hr>
           <!--c1和c2都是div的子组件-->
           <!--子父事件传值-->
           <c1 @emit='change'></c1>
           <hr>
           <!--父子属性传值-->
           <c2 :test='state'></c2>
       </div> 
       <template>
           <div>
               我是c1,是c2的兄弟
               <!--间接通过父级改变了兄弟级的值-->
               <button @click='emit'>点我我的兄弟和父级都会发生改变</button>
            </div>
       </template>
       <template>
           <div>我是c2,是c1的兄弟
               <p>{{test}}</p>
           </div>
       </template>
    </body>
    <script>
        Vue.component('c1',{
            template:'#tp1',
            methods:{
                emit(){
                    this.$emit('emit')
                }
            }
        })
        Vue.component('c2',{
            template:'#tp2',
            props:["test"]
        })
        new Vue({
            el:'#myApp',
            data:{
                state:false
            },
           methods:{
               change(){
                   this.state=!this.state
               }
           }
        })
    </script>
    </html>
    
    

    (2)公共汽车传值(声明一个公共实例作为过滤)

    修改谁的值就去触发谁的方法
    在这里插入图片描述

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>兄弟之间通过公共汽车传值</title>
        <script src="base/vue.js"></script>
    </head>
    <body>
        <div>
            <father></father>
        </div>
        <template>
            <div>我是父组件
                <hr>
                <son1></son1>
                <hr>
                <son2></son2>
            </div>
            
        </template>
        <template>
            <div>{{name}}
            <!--点击事件触发一下sclick函数,相当于把抛出的change函数触发了-->
                <button @click='sclick'>点我</button>
            </div>
        </template>
        <template>
            <div>{{name}}</div>
        </template>
    </body>
    <script>
        let Bus=new Vue();
        new Vue({
            el:'#myApp',
            components:{
                father:{
                    template:'#father',
                    components:{
                        son1:{
                            template:'#son1',
                            data(){
                                return{
                                    name:'我是子组件1'
                                }
                            },
                            methods:{
                                sclick(){
                                //触发test事件,再传一个参数給change函数中的val
                                //name值就从“我是子组件2”通过点击事件变成了"加油鸭!!!!"
                                    Bus.$emit('test',"加油鸭!!!!")
                                }
                            }
                        },
                        son2:{
                            template:'#son2',
                            data(){
                                return{
                                    name:'我是子组件2'
                                }
                            },
                            methods:{
                                change(val){
                                    this.name=val
                                }
                            },
                            mounted(){
                            //只要mounted执行了,说明组件已经准备就绪
                            //注册一个函数,函数名叫test,处理函数就是methods中的change函数
                            //简单来说,只要想办法触发test事件就相当于执行了change函数
                                Bus.$on('test',this.change)
                            }
                        }
                    }
                }
            }
        })
    </script>
    </html>
    
    

    (3)vuex(集中式的数据状态管理器)
    简单来说,就是用来管理全局变量的,不管哪里进行修改,页面都会随之变化。比如我们手机端的选择所在区域,假设你选了北京,跳到其他页面还是显示的北京就可以用vuex来实现。
    解决的问题:
    帮助我们管理共享状态。
    vuex的相关配置步骤:

    1. npm install vuex --save-dev
    2. 引入:`import Vuex from ‘vuex’
    3. 使用:Vue.use(Vuex)
    4. 设置vuex
    
    var store=new Vuex.Store({
           state:{
           },
            mutations:{
            },
            actions:{
            },
            getters:{
            }
     })
    
    
    1. 将数据放入到实例中
    
    new Vue({
      el: '#app',
      router,
      store,
      components: { App},
      template: '<App/>',
    })
    
    

    vuex中的模块:

    1. state:存储状态,可通过this.$store.state获取我们在vuex中声明的全局变量的值
    
    import Vuex from 'vuex'
    Vue.use(Vuex)
    let store=new Vuex.Store({
        state:{
            name:1,
        }
    })
    export default store;
    //一般我们会新建一个store文件夹,
    //在该文件夹的js文件中通过暴露出store,
    //再通过在main.js中引入该文件的方式来使用vuex
    
    

    在组件中我们只需要通过{{this.$store.state.name}}就可以渲染name的值
    写一个组件:

    
    <template>
        <div>
            {{msg}}
            {{this.$store.state.name}}
            <hr>
        </div>
    </template>
    
    <script>
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    

    在这里插入图片描述
    有木有觉得{{this.$store.state.name}}太长了,可不可以直接写{{name}}:

    
    <template>
        <div>
            {{msg}}
            {{name}}
            <hr>
        </div>
    </template>
    
    <script>
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        },
        computed:{
            name(){
                return this.$store.state.name
            }
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    
    

    有小伙伴会说了,这样也不简单呀,那这样呢?

    
    <template>
        <div>
            {{msg}}
            {{name}}
            <hr>
        </div>
    </template>
    
    <script>
    import {mapState} from 'vuex'
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        },
        //可不可以不用拓展操作符?可以呀
        //computed:mapState(['name'])
        //可是这样你如果还有其他的方法要在computed中操作就没法操作了
        computed:{
            ...mapState(['name'])
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    
    

    如果遇到需要改名的情况,可通过对象的形式:

    
    {{_name}} //改后的名字进行页面渲染
    ...mapState({_name:"name"})
    
    

    后面的方法基本思路一样,接下来就都用简写形式啦!
    2. mutations:修改状态

    
    import Vuex from 'vuex'
    Vue.use(Vuex)
    let store=new Vuex.Store({
        state:{
            name:1,
        },
         mutations:{
            CHANGE_NUM(state,name){
                state.name=name
            }
        },
    })
    export default store;
    
    

    我们来做一个小效果,点击按钮改变状态值从1变为888

    
    <template>
        <div>
             <div @click='CHANGE_NUM(888)'>change</div>
            {{msg}}
            {{_name}}
            <hr>
        </div>
    </template>
    
    <script>
    import {mapState,mapMutations} from 'vuex'
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        },
        methods:{
              //非简写形式,点击事件的调用方法换为getName
             //getName(){
             //    this.$store.commit('CHANGE_NUM',888)
             //     }
            ...mapMutations(['CHANGE_NUM']),
        },
        computed:{
            ...mapState({_name:'name'})
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    
    

    在这里插入图片描述
    在这里插入图片描述
    3. actions:专门用来做异步操作
    通过计时器模拟一个异步操作,并通过commit触发mutations

    
    import Vuex from 'vuex'
    Vue.use(Vuex)
    let store=new Vuex.Store({
        state:{
            name:1,
        },
         mutations:{
            CHANGE_NUM(state,name){
                state.name=name
            }
        },
         actions:{
           //逻辑处理及异步请求
           getNumApi({commit},params){
               setTimeout(()=>{
                   commit('CHANGE_NUM',params)
               },2000)
           }
        }
    })
    export default store;
    
    

    再来实现一个点击按钮改变值的效果:

    
    <template>
        <div>
             <div @click='getNumApi("xixi")'>change</div>
            {{msg}}
            {{_name}}
            <hr>
        </div>
    </template>
    
    <script>
    import {mapState,mapActions} from 'vuex'
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        },
        methods:{
            //非简写的写法:(通过dispatch触发相应的action)
             //emitActions(params){
            //     this.$store.dispatch('getNumApi',params)
            // }
            ...mapActions(['getNumApi'])
        },
        computed:{
            ...mapState({_name:'name'})
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    
    

    2秒后name值改变了
    在这里插入图片描述
    4. getters:类似于计算属性computed,里面进行一些计算操作

    
    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    let store=new Vuex.Store({
        state:{
            name:1
        },
        mutations:{
            CHANGE_NUM(state,name){
                state.name=name
            }
        },
        getters:{
            double(state){
                return state.name*2
            }
        },
        actions:{
           //逻辑处理及异步请求
           getNumApi({commit},params){
               setTimeout(()=>{
                   commit('CHANGE_NUM',params)
               },2000)
           }
        }
    })
    export default store;
    
    

    再来做点击事件:

    
    <template>
        <div>
             <div @click='getNumApi("xixi")'>change</div>
            {{msg}}
            {{_name}}
            {{double}}
            <hr>
        </div>
    </template>
    
    <script>
    import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'
    export default {
        name:'List',
        data(){
            return {
                msg:'list',
            }
        },
        methods:{
            ...mapActions(['getNumApi'])
        },
        computed:{
            ...mapState({_name:'name'}),
             ...mapGetters(['double'])
        }
    }
    </script>
    <style>
    #list div{
         50px;
        height: 50px;
        background: red;
    }
    </style>
    
    
    

    由于字符串不能进行乘法操作,所以打印结果是NaN
    在这里插入图片描述
    5. modules:模块
    在实际开发中,我们会把以上四个模块,分别写在四个js文件中,在通过引入、暴露的形式写在一个index.js文件下。

    
    import actions from './actions'
    import state from './state'
    import mutations from './mutations'
    import getters from './getters'
    
    export default {
        state,
        mutations,
        getters,
        actions
    }
    
    

    再把这5个文件放在store文件夹下的shopcar文件夹下(名字随意),在再store文件夹下,新建一个index.js文件,并通过modules的形式展现:

    
    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    import shopcar from './shopcar'
    let store=new Vuex.Store({
        modules:{
            shopcar:shopcar 
        }
    })
    export default store
    
    

    在这里插入图片描述

    来源:https://blog.csdn.net/weixin_43747906/article/details/84981199

  • 相关阅读:
    redis几种模式的部署(Windows下实现)
    servlet容器:jetty,Tomcat,JBoss
    redis三种模式对比
    Linux expect详解
    expect学习笔记及实例详解
    shell expect的简单实用
    【Spring Boot】内嵌容器
    java 怎么让打印信息换行?
    Java中的静态方法是什么?
    java的接口为什么不能实例化
  • 原文地址:https://www.cnblogs.com/qixidi/p/10185941.html
Copyright © 2020-2023  润新知