• vue第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )


    第八单元(组件通信 子父,父子组件通信 自定义事件 事件修饰符 v-model props验证 )

    #课程目标

    1. 掌握使用props让父组件给子组件传参(重点)

    2. 掌握props属性的使用以及prop验证的常用规则

    3. 掌握使用自定义事件让子组件给父组件传参(重点)

    4. 了解v-model在组件中的绑定原理,掌握组件的v-model的绑定

    5. 熟悉常用的表单修饰符、事件修饰符、键盘修饰符

    #知识点

    #1.组件间的通信方式

    #1.1父组件给子组件传递数据--使用props属性

    ​ 在父组件中动态绑定自定义的props属性来传递的数据,Parent.vue如下:

    <template>
      <div>
      	Parent
      	<br />
      	<Children :pmsg='msg'></Children>
      </div>
    </template>
    <script>
    import Children from './Children'
    export default {
      name: 'Parent',
      data () {
        return {
        	msg:'我是父组件的数据'
        }
      },
      components:{
      	Children
      }
    }
    </script>
    


    ​ 代码所示中的:pmsg(:是vue指令v-bind的缩写)则是绑定的自定义props属性名称,msg则是父组件想要给子组件传递的数据

    ​ 在子组件中使用 props 选项去接收来自父组件传递过来的数据 ,Children.vue示例代码如下:

    <template>
      <div>
      	Children
      	<br />
      	{{pmsg}}
      </div>
    </template>
    
    <script>
    export default {
      name: 'Children',
      //通过props来去接收父组件传递的值
      props:['pmsg'],
      data () {
        return {
    
        }
      }
    }
    </script>
    
     

    ​ 代码中要使用父亲传过来的参数,首先要在props中先定义父亲传过来的props属性名称,然后就可以在页面中使用父亲传过来的数据了,在此案例中,pmsg就是父组件的传到子组件中的数据了。

    ​ 注意,由于HTML特性是不区分大小写的,所以传递属性值时,如果想传递驼峰参数,pMsg应该转换成 kebab-case (短横线隔开式):p-msg='msg'。如:

    //父组件传值时  想要传pMsg  应该这样写
    <Children :p-msg='msg'></Children>
    //子组件接收的是驼峰
    props:['pMsg']
    
     

    关于props

    • 可以使用v­-bind动态绑定父组件来的内容
    • 在组件中使用props来从父组件接收参数,注意,在props中定义的属性,都可以在子组件中直接使用
    • props来自父级,而组件中data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
    • props的值有两种,一种是字符串数组,一种是对象
    • 对于数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态(尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态)
    #1.2 Prop验证

    ​ 我们可以给组件的props属性添加验证,当传入的数据不符合要求时,Vue会发出警告。

        props: {
             // 基础类型检测 (`null` 意思是任何类型都可以)
             propA: Number,
            // 多种类型
             propB: [String, Number],
            // 必传且是字符串
            propC: {
                type: String,
                required: true
            },
            // 数字,有默认值
            propD: {
                type: Number,
                default: 100
            },
            // 数组/对象的默认值应当由一个工厂函数返回
            propE: {
                type: Object,
                default: function () {
                return { message: 'hello' }
                }
            },
            // 自定义验证函数
            propF: {
                validator: function (value) {
                return value > 10
                }
            }
        }
    
     

    type 可以是下面原生构造器:

    • String
    • Number
    • Boolean
    • Function
    • Object
    • Array
    • Symbol

    ​ type 也可以是一个自定义构造器函数,使用 instanceof 检测。

    <template>
      <div>
      	<div>名字: {{ person-prop.name }}, 年龄: {{ person-prop.age }} </div>
      </div>
    </template>
    <script>
    // 自定义Person构造器  这个可以定义在外边引进来,这里只是方便教材描写演示
    function Person(name, age) {
        this.name = name
        this.age = age
    }
    export default {
      name: 'Children',
      //通过props来去接收父组件传递的值
      //如果传过来的不是Person类型会报错,比如:1,'str',等等的其他类型...
      props: {
            person-prop: {
            type: Person     // 指定类型
        	}
      },
      data () {
        return {
    
        }
      }
    }
    </script>
    
     
    #1.3 子组件给父组件传递数据--使用自定义事件

    ​ 父组件使用props传递数据给子组件,子组件怎么跟父组件通信呢?这时,Vue的自定义事件就派上用场了。接下来我们将学习Vue自定义事件。

    ​ 每个 Vue 实例都实现了事件接口 (Events interface),即:使用 $on(eventName) 监听事件、 使用 $emit(eventName) 触发事件。

    父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

    也就是说:子组件用 $emit() 来触发事件 ,父组件用 v-on来 监听子组件的事件 。

    注意:不能用 $on 侦听子组件抛出的事件,而必须在模板里直接用 v-on 绑定。

    第一步:在子组件中触发$emit自定义事件。(第一个参数是事件名,后边的参数是要传递的数据 )

    //smsg 是自定义事件的名称  
    	//和原生的click,change,keyup等等类似 
    	//上面几个分别是  点击事件的名称、数据变动事件的名称、键盘抬起事件的名称
    //data是想要传递的数据
    this.$emit('smsg',data)
    
     

    第二步:在父组件中监听自定义事件中来接收子组件的参数

    //监听原生的click事件  是@click
    //那么监听自定义事件  也是如此 @smsg
    //getMsg是函数
    	//这个函数中如果有值的传递,必须传递$event参数  $event就是子组件中传递过来的data
    	//所以可以有两种方式写
    <Children @smsg="getMsg"></Children>
    //或者
    <Children @smsg="getMsg($event)"></Children>
    
     

    子组件Children.vue具体代码:

    <template>
      <div class="cc">
      	Children
      	<br />
      	<button @click="clickMe">点击我</button>
      </div>
    </template>
    <script>
    export default {
      name: 'Children',
      data () {
        return {
        	msg:'我是子组件的数据'
        }
      },
      methods:{
      	clickMe(){
      		//子组件中先触发这个emit事件
      		this.$emit('smsg',this.msg);
      	}
      }
    }
    </script>
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    	.cc{
    		height: 100px;
    		background-color: red;
    	}
    </style>
    
     

    父组件Parent.vue具体代码:

    <template>
      <div class="pp">
      	Parent--{{msg}}
      	<br />
      	<Children @smsg="getMsg"></Children>
    	<!--也可以这样写-->
    	<!--<Children @smsg="getMsg($event)"></Children>-->
      </div>
    </template>
    <script>
    import Children from './Children'
    export default {
      name: 'Parent',
      data () {
        return {
        	msg:'我是没有改变之前的数据'
        }
      },
      methods:{
      	//this.$emit('smsg',this.msg);
      	//data这个参数 指的就是子组件中  this.msg
      	getMsg(data){
      		//console.log(msg)
      		this.msg = data;
      	}
      },
      components:{
      	Children
      }
    }
    </script>
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    	.pp{
    		height: 500px;
    		background-color: pink;
    	}
    </style>
    
    
     
    #1.4 在组件中使用 v-model

    一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。

    我们可以使用v-model来去绑定组件,试试怎么实现组件间的传值。

    首先我们得知道v-model的绑定原理:

    //正常表单绑定v-model
    //data中的msg会随着input中的值变化而变化 也就是双向绑定
    <input type="text" v-model="msg" />
    
    //不使用v-model完成数据的双向绑定
    <input type="text" @input="msg=$event.target.value" :value="msg" />
    
     

    ​ 通过上述的代码,我们已经明白了v-model的绑定原理,那么如果我们想给一个子组件上的input与父组件的某个数据做一个双向数据绑定,我们该怎么做呢?(Children组件,假定这个组件有一个input元素)

    //如果这样绑定这个v-model指令
    <Children v-model="msg"></Children>
    
    //根据之前的原理剖析,上面这个代码可以转换成:
    <Children @input="msg=$event.target.value" :value="msg"></Children>
    
     

    思考:这么写对不对呢?

    我们再看子组件Children.vue中的部分代码:

    <template>
      <div>
        //如果想要作为双向绑定,那么子组件中的值就应该往父组件中传,这里就要用到$emit去自定义事件
        //因为父组件是使用input来监听,那么我们就应该使用自定义'input'的事件触发 这里是和原生input同名而已
        //并把当前value值传给父组件
      	<input type="text" @input="$emit('input',$event.target.value)" :value="value" />
      </div>
    </template>
    
    //既然父组件传了prop名为value的的值,那么props中应该定义一个value
    props:['value']
    
     

    写到这里我们打开浏览器会发现,我们并没有实现双向绑定,为什么呢?

    我们再回顾一下,在讲父组件监听自定义事件的时候,说过参数$event就是子组件传回来的参数。

    那么,在父组件中,我们应该改为:

    <Children @input="msg=$event" :value="msg"></Children>
    
     

    到此为止,我们就实现了父组件与子组件中表单元素的双向绑定

    #2.修饰符

    #2.1表单修饰符

    (1).lazy

    在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步。

    如下,示例:

    <!-- 在“change”时而非“input”时更新 -->
    <input v-model.lazy="msg" />
    
     

    (2).number

    如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符。

    如下,示例:

    <input v-model.number="age" />
    
     

    (3).trim

    如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符。

    如下,示例:

    <input v-model.trim="msg" />
    
     
    #2.2事件修饰符

    在Vue中,事件修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。在Vue中事件修饰符主要有:

    • .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡
    • .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
    • .capture:与事件冒泡的方向相反,事件捕获由外到内
    • .self:只会触发自己范围内的事件,不包含子元素
    • .once:只会触发一次

    .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡

    <div id="app"> 
      <div class="outeer" @click.stop="outer"> 
        <div class="middle" @click.stop="middle"> 
          <button @click.stop="inner">点击我</button>
         </div>
       </div> 
    </div>
    
     

    .prevent取消默认事件

    .prevent等同于JavaScript的event.preventDefault(),用于取消默认事件。

    <!--不会跳转到另外一个页面-->
    <a href="https://www.baidu.com" @click.prevent="clickMe"></a>
    
     

    .capture 捕获事件

    捕获事件:嵌套两三层父子关系,然后所有都有点击事件,点击子节点,就会触发从外至内 父节点 ==>子节点的点击事件

    <div class="outeer" @click.capture="outer"> 
        <div class="middle" @click.capture="middle"> 
        	<button @click.capture="inner">点击我</button>
        </div>
    </div> 
    
     

    .self

    修饰符.self只会触发自己范围内的事件,不会包含子元素。

    <div class="outeer" @click.self="outer"> 
        <div class="middle" @click.self="middle"> 
        	<button @click.stop="inner">点击我</button>
        </div>
    </div> 
    
     

    .once 只执行一次点击

    如果我们在@click事件上添加.once修饰符,只要点击按钮只会执行一次。

    #2.3键盘修饰符

    在JavaScript事件中除了前面所说的事件,还有键盘事件,也经常需要监测常见的键值。在Vue中允许v-on在监听键盘事件时添加关键修饰符。记住所有的keyCode比较困难,所以Vue为最常用的键盘事件提供了别名:

    • .enter:回车键
    • .tab:制表键
    • .delete:含deletebackspace
    • .esc:返回键
    • .space: 空格键
    • .up:向上键
    • .down:向下键
    • .left:向左键
    • .right:向右键

    #授课思路

    #案例和作业

    使用组件方式实现弹窗

  • 相关阅读:
    02:找第一个只出现一次的字符
    11-Canvas
    07-jQuery
    06-JavaScript高级
    05-Web API
    03-京东项目
    剑与远征-兑换码
    04-JavaScript基础语法
    02-CSS
    01-HTML
  • 原文地址:https://www.cnblogs.com/yzy521/p/14132018.html
Copyright © 2020-2023  润新知