四,组件化开发(三)之数据

1. 组件数据存放

  • 组件是一个单独功能模块的封装,这个模块有自己HTML模板,也应该有自己的数据data。

  • 那么组件的数据存放在哪里呢?组件能直接访问顶层的vue实例中的数据吗?

  • 我们发现不能直接访问顶层的vue实例中的数据。

  • 因此组件应该有自己存放数据的地方。

  • 组件对象也有一个data属性

  • 这个属性必须是一个函数

    • 如果不是一个函数,Vue直接就会报错
    • Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
  • 而且这个函数返回一个对象,对象内部保存着数据

全局组件的数据存放

<template id="cpn1">
    <div>
        <h1>{{title}}</h1>
        <p>这是全局组件中数据存放</p>
    </div>
</template>

<script src="../js/vue.js"></script>
<script type="text/javascript">

    Vue.component('cpn1',{
        template: '#cpn1',
        data(){
            return{
                title: 'bbbb'
            }
        }
    }) 
</script>

局部组件的数据存放

<template id="cpn">
    <div>
    <h1>{{title}}</h1>
        <p>这是局部组件中数据存放</p>
    </div>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">

    //局部组件的数据存放
    var app= new Vue({
            el: "#app",
            data: {
                message:'小贱'
            },
            components:{
                'cpn':{
                    template:'#cpn',
                    data(){
                        return {
                            title : 'aaaaa'
                        }
                    }
                },
            }
        })
</script>

2. 父子组件之间的通信

  • 从数据的存放中我们得知子组件是不能引用父组件或者vue实例的数据的。
  • 但是往往在开发中,一些数据需要从上层传递到下层
  • 如何进行父子组件之间的通信,官方提到
    • 父组件通过props向子组件传递数据
    • 子组件通过事件向父组件传递消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6PjS8V9p-1595236228981)(vue-images/Snipaste_2020-07-07_17-43-51.png)]

1. 父传子(props)
  • 字符串数组,数组中的字符串就是传递时的名称

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYiZQTN3-1595236228984)(vue-images/Snipaste_2020-07-09_18-36-39.png)]

  • 对象,对象可以设置传递时的类型,也可以设置默认值

  • 当我们需要对props进行数据类型的验证的时候就需要用到对象类型了

    • 支持验证的数据类型
    • String , Number , Boolean , Array , Object , Date ,Function , Symbol
<body>
<div id="app">
    //此处用到props的驼峰命名规则   c-message
    <cpn1 :c-message="message" :removies="movies"></cpn1>
    <cpn2 :message="message"></cpn2>
</div>

<template id="cpn">
    <div>
        <ul>
            <li v-for="item in removies">{{item}}</li>
        </ul>
        <h2>{{cMessage}}</h2>
    </div>
</template>

<template id="cpn2">
    <h2>数组、:{{message}}</h2>
</template>

<script src="../js/vue.js"></script>
<script type="text/javascript">


    //父传子  props
    var cpn = {
        template: '#cpn',
        props:{
            cMessage:{
                type: String,
                default: 'aaaaa'
            },
            //类型时对象或者数组的时候,默认值必须是一个函数
            removies: {
                type: Array,
                default(){
                    return []
                }
            }
        }
    }
    const app= new Vue({
            el: "#app",
            data: {
                message: "hello vue",
                movies: ['红楼梦','水浒','三国演义','西游记']
            },
            components:{
               cpn1:cpn ,
                cpn2:{
                   template: '#cpn2',
                    props: ['message']
                }
            }
        })
</script>
</body>
2. 子传父(事件)
  • 我们可以通过自定义事件使子组件可以向父组件传递数据
  • v-on不仅可以监听DOM事件,也可以用来自定义事件
  • 流程
    • 子组件通过$emit()触发事件
    • 父组件通过v-on监听事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    
    //监听+-的次数
</head>
<body>

<div id="app">
    <child-cpn @increment='changeTotal' @decrement="changeTotal"></child-cpn>
    <h2>点击次数:{{total}}</h2>
</div>

<template id="cpn">
    <div>
        <button @click="increment">+1</button>
        <button @click="decrement">-1</button>
    </div>
</template>

<script src="../js/vue.js"></script>
<script type="text/javascript">


    var app= new Vue({
            el: "#app",
            data: {
            total:0
            },
            methods:{
              changeTotal(counter){
                  this.total=counter
              }
            },
            components: {
                'child-cpn':{
                    template:"#cpn",
                    data(){
                        return{
                            counter:0
                        }
                    },
                    methods:{
                        increment(){
                            this.counter++
                            //发送一个事件$emit
                            this.$emit('increment',this.counter)
                        },
                        decrement(){
                            this.counter--
                            this.$emit('decrement',this.counter)
                        }
                    }
                }
            }
        })
</script>

</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <cpn @item-click="cpnClick"></cpn>
</div>

<template id="cpn">
    <div>
        <button v-for="item in categories"
        @click="btnClick(item)">
            {{item.name}}
        </button>
    </div>
</template>

<script src="../js/vue.js"></script>
<script type="text/javascript">

    const cpn= {
        template: '#cpn',
        data(){
            return{
                categories:[
                    {id: 'aaa',name:'热门推荐'},
                    {id: 'bbb',name:'手机数码'},
                    {id: 'ccc',name:'家用家电'},
                    {id: 'ddd',name:'电脑办公'}
                    ]
            }
        },
        methods:{
            btnClick(item){
                this.$emit('item-click',item)
            }
        }
    }
    
    const app= new Vue({
            el: "#app",
            data: {
                message: "hello vue"
            },
            components: {
                cpn:cpn
            },
            methods:{
                cpnClick(item){
                    console.log('cpnClick',item)
                }
            }
        })
</script>
</body>
</html>

3.父子组件之间的访问

1. 父组件访问子组件
  • $children

    • this.$children是一个数组类型,包含所有的子组件对象
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <cpn></cpn>
        <button @click="btnClick">按钮</button>
    </div>
    
    <template id="cpn">
        <div>我是子组件</div>
    </template>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
    
    
    
        var app= new Vue({
                el: "#app",
                data: {
                    message: "hello vue"
                },
                methods:{
                  btnClick(){
    
                      //$children
                      console.log(this.$children)
                       for(let c of this.$children){
                           console.log(c.name);
                           c.showMessage()
                       }
    
                     // console.log(this.$children[1].name)
                  }
                },
                components: {
                    cpn: {
                        template: '#cpn',
                        data(){
                            return{
                                name: '我是子组件的name'
                            }
                        },
                        methods: {
                            showMessage(){
                                console.log('showMessage!!!')
                            }
                        }
                    }
    
                }
            })
    </script>
    
    </body>
    </html>
    
  • $refs

    • 通过$children访问子组件的时候,因为是一个数组类型,访问子组件必须通过其索引值
    • 当子组件过多的时候,我们往往不能确定其子组件的索引
    • 当我们想明确的取出其中的一个特定的子组件,可以使用$refs
  • $refs的使用

    • $refs和ref指令一起使用
    • 通过ref给组件添加一个特定的ID
    • 通过this.$refs.ID就可以访问该组件
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <my-cpn></my-cpn>
        <y-cpn></y-cpn>
        <cpn ref="xiaojian"></cpn>
    </div>
    
    <template id="cpn">
        <div>我是子组件</div>
    </template>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
    
    
    
        var app= new Vue({
                el: "#app",
                data: {
                    message: "hello vue"
                },
                methods:{
                  btnClick(){
    
                      //2.$refs  对象类型  默认的是一个空的对象
                      console.log(this.$refs.xiaojian.name)
                  }
                },
                components: {
                    cpn: {
                        template: '#cpn',
                        data(){
                            return{
                                name: '我是子组件的name'
                            }
                        },
                        methods: {
                            showMessage(){
                                console.log('showMessage!!!')
                            }
                        }
                    }
                }
            })
    </script>
    
    </body>
    </html>
    
2. 子组件访问父组件
  • 在开发中我们可以通过$parent来控制子组件访问父组件
  • 但是子组件应该尽量避免直接访问父组件的数据,这样代码间的耦合度太高
  • 通过$parent 可能直接修改父组件的状态,这样的话父组件的状态将会变得飘忽不定,很不利于维护和开发
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <cpn></cpn>
</div>

<template id="cpn">
    <div>
        <h2>我是cpn组件</h2>
        <ccpn></ccpn>
    </div>

</template>

<template id="ccpn">
    <div>
        <h2>我是ccpn子组件</h2>
        <button @click="btnClick">按钮</button>
    </div>

</template>

<script src="../js/vue.js"></script>
<script type="text/javascript">
    var app= new Vue({
            el: "#app",
            data: {
                message: "hello vue"
            },
            components:{
                cpn: {
                    template:'#cpn',
                    data(){
                        return{
                            name: '我是父组件的cpn'
                        }
                    },
                    components: {
                        ccpn: {
                            template: '#ccpn',
                            methods:{
                                btnClick(){
                                    console.log(this.$parent.name);
                                    console.log(this.$root.message)
                                }
                            }
                        }
                    }
                }
            }
        })
</script>

</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值