16-不得不学的Vue.js基础之自定义事件

前端 · 2020-07-22 ·
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>自定义事件</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <!--1.事件名:我们推荐你始终使用 kebab-case(短横线) 的事件名-->

        <!--2.自定义组件的 v-model:一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的 event,但是像单选框、复选框等类型的输入控件可能会将 value 属性用于不同的目的。model 选项可以用来避免这样的冲突-->
        <!--这里的 lovingVue 的值会传入这个名为 checked 的prop,当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新-->
        <p>
        	<base-checkbox v-model="lovingVue"></base-checkbox> 选择
        </p>

        <!--3.将原生事件绑定到组件:在根元素上直接监听一个原生事件,这是可以通过 v-on 的 .native 修饰符-->
        <!--3.1 首先定义个 base-button 组件,添加handleClick方法,当我们点击这个组件,并没有 输出对应的信息“base-button clicked!”-->
        <!--这个时候.native 修饰符就提现出他的作用,我们加上此修饰符,此时点击按钮输出对应的信息“base-button clicked!”-->
        <!--.native的作用:监听组件根元素的原生事件!除此之外,我们也可以通过 $emit 事件派发给父组件-->
        <p>
			<base-button v-on:click.native="handleClick"></base-button>
        </p>
        <p>
			<base-button2 v-on:click="handleClick2"></base-button2>
        </p>
        <!--3.2 native修饰符:将原生事件绑定到组件的根元素上,但是有的时候根元素并没有原生事件。比如如下全局组件3.3,根元素实际上是 <label>,就不能使用如上重构,这是父级的 .native 监听器将静默失败。-->
        <!--为了解决这个问题,Vue 提供了一个 $listeners property,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如
		{
			focus:function (event){
				/*...*/
			}
			input:function (event){
				/*...*/
			}
		}
        -->
        <!--现在 <base-input> 组件是可以完全像一个普通的 <input> 元素一样使用了:所有跟他相同的attribute 和 监听器都可以工作,不必再使用.native 监听器。-->
        <p>
        	<base-input label="price" placeholder="placeholder" v-model="price"></base-input>
        </p>	

        <!--4. sync修饰符:语法糖,它会被扩展为一个自动更新父组件属性的 v-on 监听器,既子组件改变某个prop 的时候,来变更父组件的状态值进而变更子组件状态。-->
        <!--
		<comp v-bind:foo.sync="bar"></comp>
		会被扩展为
		<comp v-bind:foo="bar" v-on:update:foo="val => bar = val"></comp>
		当子组件更新foo的值时,它就触发一个更新事件
		this.$emit('update:foo',newValue)
        -->
		<p>
			<base-toggle :show.sync='ifshow'></base-toggle>
			<button @click="changeIfshow">toggle</button>
		</p>


    </div>
    <script>
    // 2.注册全局组件base-checkbox!
    Vue.component('base-checkbox', {
        model: {
            prop: 'checked',
            event: 'change'
        },
        props: {
            checked: Boolean
        },
        template: `
		    <input
		      type="checkbox"
		      v-bind:checked="checked"
		      v-on:change="$emit('change', $event.target.checked)"
		    >
		  `
    });
    // 3.1注册全局组件base-button!
    Vue.component('base-button',{
    	template:`
			<button>Click Me</button>
    	`
    });
    // 3.2注册全局组件base-button2!
    Vue.component('base-button2',{
    	template:`
			<button v-on:click="click">Click Me2</button>
    	`,
    	methods:{
    		click(){
    			this.$emit('click',"I am form child!")
    		}
    	}
    });
    // 3.3注册全局组件base-input!
    Vue.component('base-input',{
    	inheritAttrs: false,
    	props:['label','value'],
    	computed:{
    		inputListeners:function(){
    			var vm =this;
    			//`Object.assign` 将所有的对象合并为一个新对象
    			return Object.assign({},
    				this.$listeners,
    				// 然后我们添加自定义监听器,
    				// 或覆写一些监听器的行为
    				{
    					// 这里确保组件配合 `v-model` 的工作
    					input:function(event){
    						vm.$emit('input',event.target.value)
    					},
    					focus:function(event) {
    						console.log('onFocus 事件')
    					}
    				}

    			)
    		}	
    	},
    	template:`
			<label>
			  {{ label }}
			  <input
			    v-bind="$attrs"
			    v-bind:value="value"
			    v-on="inputListeners"
			  >
			</label>
    	`,
    	methods:{
    		click(){
    			this.$emit('click',"I am form child!")
    		}
    	}
    });

    // 4.注册全局组件base-toggle!
    Vue.component('base-toggle',{
    	template:`
			<div>
                <p v-if="show">默认初始值是{{show}},所以是显示的</p>
                <button @click.stop="closeDiv">关闭</button>
            </div>
    	`,
    	props:['show'],
    	methods:{
    		closeDiv(){
    			this.$emit('update:show',false);
    		}
    	}
    });
    var vm = new Vue({
        el: "#app",
        data:{
        	lovingVue: true,
        	price:0,
        	ifshow:true
        },
        methods:{
        	handleClick(){
        		console.log("base-button clicked!");
        	},
        	handleClick2(val){
        		console.log(val);
        	},
        	changeIfshow(){
        		this.ifshow = !this.ifshow;
        	}
        }
    });
    </script>
</body>

</html>

以下是测试数据:

选择

%