zoukankan      html  css  js  c++  java
  • Vue学习-组件中的数据通信

    组件可以访问Vue实例数据吗?

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

    • 组件中不能直接访问Vue实例里的数据,以下代码在组件是不能访问到message的

    <div id="app">
         <hello></hello>
    </div>
    
    <template id="myId">
          <div>消息内容:{{message}}</div>
    </template>
    
    <script src="vue.js"></script>
    <script>
    let app=new Vue({
          el:"#app",
          data:{
               message:"hello world"
          },
          components:{
                'hello':{
                      template:"#myId"
                }
          }
    })
    </script>
    

    组件的data参数

    • 组件定义时也有一个data参数,但这个data参数不像Vue实例的data是一个对象类型,它这里是一个函数类型,如果你定义成了一个对象类型,会报以下错误
    • 该data函数需要返回一个对象,对象内部保存着数据
    • 示例代码:https://jsrun.net/EevKp/edit
    const cpnC = Vue.extend({
        template: "#cpn",
        data(){
            return {
                title:"这里是标题吧",
                content:"这里是内容哦!~~"
            }
        }
    })
    

    组件中的methods函数

    const cpnC = Vue.extend({
        template: "#cpn",
        data(){
            return {
                counter:0
            }
        },
        methods:{
            increment:function(){
                this.counter++
            },
            decrement:function(){
                this.counter--
            }
        }
    })
    

    父子组件

    使用场景

    • 比如一个商城的首页,上面有一个轮播图,下面有一个商品的列表
    • 像这种页面,我们在开发时,会在最外层组件(父组件)里,向服务端一次请求到轮播图,商品列表数据,然后将数据分别传给轮播图组件,商品列表组件;然后商品列表组件在将数据传传商品组件来进行整个页面的渲染

    如何通信(传递数据)

    • Vue实例也可以看作一个父组件

    父传子

    • 通过prots向子组件传数据(protsproterties的简写,意为属性
    • props的二种方式
      1.一种是可以传一个字符串数组,里面第一项对应变量名
      将godos和message传给子组件进行渲染,示例代码:http://jsrun.net/5PvKp/edit
    <div id="app">
    	<my-cpn v-bind:cgoods="goods" :cmessage="message"></my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn1">
    	<div>
    		<h2>{{cmessage}}</h2>
    		<ul>
                <li v-for="item in cgoods">{{item}}</li>
            </ul>
    	</div>
    </script>
    
    
    //1.Vue.extend创建组件
    const cpnC = Vue.extend({
        template: "#cpn1",
        props:['cgoods','cmessage']
    })
    
    //2.注册组件
    Vue.component('my-cpn', cpnC)
    
    const app = new Vue({
        el: "#app",
        data: {
            message: "我是message",
            goods:["衣服","鞋子","帽子","短裤"]
        }
    })
    
    

    2.第二种是传一个对象类型,可以进行类型限制type和默认值default,是否必需reauired
    type-指定参数的类型,有:String,Array,Boolean,Number,Date,Function,Symbol
    default-指定默认值
    reauired-指定是否必须要传该参数,是boolean类型,传(true或false)

    const cpnC = Vue.extend({
        template: "#cpn1",
        props: {
            //1.类型限制
            // cgoods: Array,
            // cmessage: String
    
            //2.提供默认值,没传时显示
            cgoods:{
                type:Array,
                default:[]
            },
            cmessage:{
                type:String,
                default:"这里是默认值",
                required:true
            }
        }
    })
    
    
    • props的一些使用示例
    Vue.component('cnp',{
          props:{
                //1.基础的类型检查(null匹配任何类型)
                propA:Number,
                //2.多个可能的类型
                propB:[String,Number],
                //3.必填的字符串
                propC:{
                      type:String,
                      required:true
                },
                //4.带有默认值的数字
                propD:{
                      type:Number,
                      default:100
                },
                //5.默认值的对象,数组或对象的需要返回一个函数
                propE:{
                      type:Object,
                      default:function(){
                            return {name:"hello"}
                      }
                },
                //6.带自定义验证函数
                propF:{
                      validator:function(val){
                            //这个val必须匹配下列数组中的一个
                            return ['张三','李四','王五'].indexOf(val) !== -1
                      }
                }
          }
    })
    
    • 组件中驼峰标识,props中定义了cTitle,但在组件使用是需要变为:c-title,子组件中使用时又为cTitle
    <div id="app">
    	<my-cpn :c-title="title"></my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn1">
    	<div>
            <h1>{{cTitle}}</h1>
    	</div>
    </script>
    
    
    //1.Vue.extend创建组件
    const cpnC = Vue.extend({
        template: "#cpn1",
        props: {
            //驼峰标识
            cTitle:{
                type:String
            }
        }
    })
    
    //2.注册组件
    Vue.component('my-cpn', cpnC)
    
    const app = new Vue({
        el: "#app",
        data: {
            title:"我是驼峰标识"
        }
    })
    

    子传父

    <div id="app">
    	<my-cpn @itemclick="btnClick"></my-cpn>
    	<h3>{{message}}</h3>
    	<image width="200px" :src="imgUrl"></image>
    </div>
    
    <script type="text/x-template" id="cpn1">
    	<div>
    	   <button @click="btnclick(stu)" v-for="stu in students">
                  {{stu.name}}
              </button>
    	</div>
    </script>
    
    //1.Vue.extend创建组件
    const cpnC = Vue.extend({
        template: "#cpn1",
        data: function () {
            return {
                students: [
                    { id: "001", name: "关晓彤",imgUrl:"https://5b0988e595225.cdn.sohucs.com/images/20181224/ecf125cb199d4808a067f682c6c5e6c6.jpeg" },
                    { id: "002", name: "迪丽热巴",imgUrl:"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1593861542943&di=9fe9365124a4aae6cc6cf483aa2a9e18&imgtype=0&src=http%3A%2F%2Fb.hiphotos.baidu.com%2Fzhidao%2Fwh%253D680%252C800%2Fsign%3Dbb541c4377f40ad115b1cfe56f1c3de7%2F50da81cb39dbb6fde349ce5d0524ab18972b37be.jpg" },
                    { id: "003", name: "郑爽",imgUrl:"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1593861570612&di=60b6d39dcbac9e1ea77b747d42f9f19d&imgtype=0&src=http%3A%2F%2Ftc.sinaimg.cn%2Fmaxwidth.800%2Ftc.service.weibo.com%2Fmmbiz_qpic_cn%2F1ab918195e7c8a94cc6c95182fbde786.jpg" },
                    { id: "004", name: "杨幂",imgUrl:"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1593861759697&di=6771e7279c145513968ce221a29a6b0e&imgtype=0&src=http%3A%2F%2Fphotocdn.sohu.com%2F20130816%2FImg384334041.jpg" }
                ]
            }
        },
        methods: {
            btnclick(item) {
                //发射事件,自定义事件
                this.$emit("itemclick", item)
            }
        }
    })
    
    const app = new Vue({
        el: "#app",
        components: {
            "my-cpn": cpnC
        },
        data: {
            message: "",
            imgUrl:""
        },
        methods: {
            btnClick: function (item) {
                this.message = "你选择了:" + item.name + ",学号:" + item.id
                this.imgUrl=item.imgUrl
            }
        }
    })
    

    组件中的双向绑定

    <div id="app">
    	<my-cpn :number1="num"></my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div>
    		<h2>{{dnumber}}</h2>
    	    <input type="text" :value="dnumber" @input="numInput"></input>
    	</div>
    </script>
    
    
    //1.Vue.extend创建组件
    const cpnC = Vue.extend({
        template: "#cpn",
        data(){
            return {
                dnumber:this.number1
            }
        },
        props:{
            number1:{
                type:Number,
                default:0
            }
        },
        methods:{
            numInput:function(event){
                this.dnumber=event.target.value
            }
        }
    })
    
    const app = new Vue({
        el: "#app",
        components:{
            'my-cpn':cpnC
        },
        data: {
            num: 1
        }
    })
    
    

    父组件访问子组件($children或$refs)

    • $children-是一个数组,通过下标访问,这种方式不建议使用,因为组件变化维护后,相应的下标也要变化,后期难维护
      示例代码:http://jsrun.net/VcvKp/edit
    <div id="app">
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <button @click="btnClick">点击</button>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div>
    		<h2>{{title}}</h2>
    	</div>
    </script>
    
    const app = new Vue({
        el: "#app",
        methods:{
            btnClick:function(){
                //1.$children是一个数组
                alert(this.$children[0].title)
            },
        },
        components:{
            'my-cpn':{
                template:"#cpn",
                data(){
                    return {
                        title:"我是子组件的标题"
                    }
                }
            }
        }
    })
    
    <div id="app">
        <my-cpn ref="aaa"></my-cpn>
        <my-cpn ref="bbb"></my-cpn>
        <button @click="btnClick">点击</button>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div>
    		<h2>{{title}}</h2>
    	</div>
    </script>
    
    const app = new Vue({
        el: "#app",
        methods:{
            btnClick:function(){
                //1.$children是一个数组
                //alert(this.$children[0].title)
    
                alert(this.$refs.aaa.title)
            },
        },
        components:{
            'my-cpn':{
                template:"#cpn",
                data(){
                    return {
                        title:"我是子组件的标题"
                    }
                }
            }
        }
    })
    

    子组件访问父组件($parent)

    • 子组件通过$parent访问父组件
    • $root可以用来访问根组件,一般是Vue实例
      示例代码:http://jsrun.net/dcvKp/edit
    <div id="app" class="main">
        <h2>{{message}}</h2>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div class="cpn">
    	我是子组件
    	<button @click="btnClick">点击</button>
    	</div>
    </script>
    
    const app = new Vue({
        el: "#app",
        data: {
            message: "我是Vue标题"
        },
        components: {
            'my-cpn': {
                template: "#cpn",
                methods: {
                    btnClick: function () {
                        alert(this.$parent.message)
                        //访问根组件还可以使用$root,根组件一般是Vue实例
                        //我们这里的parent就等于根组件
                        //alert(this.$root.message)
                    }
                }
            }
        }
    })
    

    组件的扩展-slot

    基本使用

    <div id="app" class="main">
    	<h2>{{message}}</h2>
    	<my-cpn>
            <span>我是slot</span>
        </my-cpn>
        <my-cpn>
            <button>我是slot按钮</button>
            <sapn>我是slot span</sapn>
        </my-cpn>
        <my-cpn></my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div class="cpn">
    	    我是组件
            <div class="div-slot">
                <slot><i>我是slot的默认值</i></slot>
            </div>
    	</div>
    </script>
    
    const app = new Vue({
        el: "#app",
        data: {
            message: "我是Vue标题"
        },
        components: {
            'my-cpn': {
                template: "#cpn"
            }
        }
    })
    

    具名插槽

    <div id="app" class="main">
    	<h2>{{message}}</h2>
    	<my-cpn></my-cpn>
    	<my-cpn>
    		<span slot="center" style="color:red">center</span>
        </my-cpn>
        <my-cpn>
           <span slot="right" style="color:red">right</span>
           <span slot="left" style="color:red">right</span>
        </my-cpn>
    </div>
    
    <script type="text/x-template" id="cpn">
    	<div class="cpn">
    	    我是组件-具名插槽
            <div class="div-slot">
                <slot name="left"><i>左边</i></slot>
                <slot name="center"><i>中间</i></slot>
                <slot name="right"><i>右边</i></slot>
            </div>
    	</div>
    </script>
    
    const app = new Vue({
        el: "#app",
        data: {
            message: "我是Vue标题"
        },
        components: {
            'my-cpn': {
                template: "#cpn"
            }
        }
    })
    
  • 相关阅读:
    Vue-CLI项目-axios模块前后端交互(类似ajax提交)
    Vue-CLI项目中路由传参
    HTML标签嵌套规则
    POJ1050 To the Max
    POJ2488 A Knight's Journey
    POJ1083 Moving Tables
    洛谷P1265 公路修建
    POJ2236 Wireless Network
    洛谷P1991 无线通讯网
    POJ1018 Communication System
  • 原文地址:https://www.cnblogs.com/bqh10086/p/13212271.html
Copyright © 2011-2022 走看看