赞
踩
大部分组件相同的三大特性:
类比系统提供的组件:
定义组件,相当于自己定义了一个标签,系统不认识,是借助于框架来解析的
组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,我们需要通过子组件的 props 选项。
子组件要显式地用 props 选项声明它期待获得的数据:
props 里声明的数据在组件中写上驼峰命名法,因为属性名要符合变量名的命名规则;在行间中写烤串命名法,
为组件的 props 指定验证规格
要指定验证规格,需要用对象的形式,而不能用字符串数组:
type 可以是下面原生构造器:
type 也可以是一个自定义构造器函数,使用 instanceof 检测。
在props里 ,如果传递的type类型是对象,其默认值必须设置为函数,这个函数return出默认的对象
{{list.lis}}
这样才能找到[1,2,3]注意 props 会在组件实例创建之前进行校验,所以在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还无法使用。
还可以不用type,自定义验证规则
Vue.component('custom-dialog', {
//props:['title'],
props: {
title: {
type:String,
default: '标题'
},
num: {
validator(value){ // 自定义验证规则
console.log(value);
return value > 10;
}
},
num: [Number,String,Array],
okValue:{
type: String,
required: true
},
list: {
type: Object, // 类型为对象,默认值default必须设置为函数,在函数中返回默认的对象
return {
lis:[1,2,3]
}
}
}
});
子组件向父组件通信:用自定义事件
在子组件中发布一个事件,父组件如果关心这个事件,就会注册这个事件的处理函数(监控这个事件)
在组件里不应该做具体的事情,应该把选择权交给使用者
怎么做到?发生某个事件时,不自己做具体的事情,而是通知父组件,告诉它我的某个状态要变化了,关心的话就监控(绑定点击的事件处理函数)
类比系统提供的组件:
比如input,select,textarea等等
共同特点:有差不多的样式,定制化,比如input的type属性传入text,button color(拾色器) date(日历)等等,有定制的功能
<input type="text" name="" value="123" a=10>
<input type="text" name="" value="456">
<input type="color" id="html5colorpicker" onchange="clickColor(0, -1, -1, 5)" value="#ff0000" style="width:85%;">
<input type="date" name="user_date" />
比如两个下拉框
共同的功能是点击时下拉框出现,这是内部的状态,不会影响外部;
如果外部想根据选择的值相应的做一些事情,怎么知道什么时候值变了?答:监控onchange事件,这个事件是系统提供的
自己定义的组件没有现成的事件,所以仿照系统的事件自定义一个事件;
<select id="selectNode">
<option>567</option>
<option>123</option>
</select>
<select id="selectNode2">
<option>567</option>
<option>123</option>
</select>
简易弹框组件的顶订阅发布模式分析(完整代码见最后)
需求:
分析
1.因为是弹框的点击事件触发的一系列操作,所以由弹框组件c-dialog发布消息(点击确定按钮时发布自定义的confirm事件)
2.弹框1的确定按钮想要控制的是div1,div1不是组件里的元素,是全局的元素,所以要在new Vue里操控。
3.弹框2的确定按钮想要控制的是div2,div2是组件c-button的元素,所以由c-button操控,因而c-button把一个自己的函数confirmFn2放在confirm事件上,监控confirm事件什么时候发生
通俗版分析
div1是在 点击弹框1的确定按钮时 隐藏,所以要知道弹框1的确定按钮什么时候被点击了
div2是在 点击弹框2的确定按钮时 变颜色,所以要知道弹框2的确定按钮什么时候被点击了
div1不在c-dialog组件里,而是在c-dialog组件的父组件里
div2也不在c-dialog组件里,在c-button组件里(也就是c-dialog的父组件里)
怎么知道?
父子之间的通信方法
父组件想知道子组件的确定按钮啥时候被点击,父子约定一个自定义事件ok。
对于弹框1:
爸爸相当于new Vue这个实例对象,孩子是c-dialog组件
爸爸派一个自己的亲信(confirmFn1函数)绑定在孩子的ok事件上,监听ok事件
孩子在自己的确定按钮上绑一个confirmHandle函数,监听按钮啥时候被点击。按钮被点击时,confirmHandle函数执行,通过$emit发布confirm事件,告诉爸爸:“confirm事件触发了,您可以做想做的事情了(把您的div1隐藏)”;
爸爸派的亲信confirmFn1函数监听到孩子喊的话,开始执行,把div1隐藏
c-button组件想知道弹框2的确定按钮啥时候被点击
对于弹框2:
爸爸是c-button组件,孩子是弹框2(c-dialog组件)
爸爸派一个自己的亲信(confirmFn2函数)绑定在孩子的confirm事件上,监听ok事件
弹框2确定按钮被点击时,confirmHandle函数执行,通过$emit发布ok事件,告诉爸爸:“confirm事件触发了,您可以把您的div2改颜色了”;
爸爸派的亲信confirmFn2函数监听到孩子喊的话,开始执行,把div2改颜色
制的结构要写在组件的标签对之间,参考原生的标签fieldset
定制的结构插入到哪里?
vue提供了一个插槽标签" ,这对标签的位置就是要插入的位置
<slot></slot>
slot标签放在哪,就会把组件的标签对之间的结构全部放在哪(注意:行间有slot属性的结构除外!!)
如果没有slot标签,组件标签对之间的结构就会丢弃
在 标签中的任何内容都被视为备用内容:
<content></content>
标签对里里放入<slot>1111111<slot>
,1111111就是备用内容除非子组件模板包含至少一个 <slot插口,否则父组件的内容将会被丢弃。当子组件模板只有一个没有属性的插槽时,父组件整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。
最初在 <slot标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
放在哪,就会把组件的标签对之间的结构全部放在哪
如果不想把标签对之间的结构放在slot标签所在的位置,想要放在其他位置(想要定义多个地方的结构),就要用到具名slot
<slot>
元素可以用一个特殊的属性name
来配置如何分发内容。多个 slot 可以有不同的名字,具名 slot 将匹配内容片段中有对应slot
特性的元素。仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。
比如:
想要把某个标签对里的结构换成自己定制的结构:
例子:把两个button按钮替换成一个p标签
<slot name="footer-slot">
<button>{{cancelValue}}</button>
<button @click="okHandle">{{okValue}}</button>
</slot>
<p slot="footer-slot">我是第二个定制的content结构</p>
具名slot的批量插入或替换
用template标签包起来,整体在template标签的行间叫一下这个slot的名字
比如下面例子:哪个slot标签的名字是footer-slot,就把哪个slot标签对里的结构内容替换为这几个span标签
<template slot="footer-slot">
<span>我是按钮</span>
<span>我是按钮</span>
<span>我是按钮</span>
<span>我是按钮</span>
</template>
###非父子组件之间的通信
在简单的场景下,可以使用一个空的 Vue 实例作为中央事件总线:
- bus.$emit表示发布
- bus.$on表示注册
例子:custom-test2关心custom-test1的button什么时候被点击
var bus = new Vue();//中央事件总线
Vue.component("custom-test1", {
template: `
<button @click="okHandle">确定</button>
`,
//组件custom-test1发生点击事件时,okHandle执行,让bus帮忙发布ok事件(类似于广播)
methods: {
okHandle(){
console.log("我点了确定");
bus.$emit("ok");
}
}
})
Vue.component("custom-test2", {
mounted(){
//通过bus订阅了ok事件,并且把自己的handle函数作为ok的事件处理函数绑在ok事件上
//这样,一旦监听到ok事件,就会执行this.handle函数,做一些事情
bus.$on("ok",this.handle)
},
template: `
<button>返回</button>
`,
methods: {
handle(){
console.log("我监听到了你的的变化");
}
}
})
new Vue({
el: '#box'
})
类比理解:
函数fn1和fn2都要使用a变量,那么a变量应该放在二者都能访问到的位置
let a = 1;
function fn1(){
}
function fn2(){
}
简易弹框组件
html
<div id="box">
<div id="div1" ref="div1">控制我隐藏</div>
<c-dialog
title="警告"
confirm-value="确定"
num="110"
@confirm="confirmFn1"
>
<ul>
<li>我是定制的content里的结构</li>
<li>我是定制的content里的结构</li>
</ul>
</c-dialog>
<!-- 注意,num="0"的0代表字符串 :num="0"的0代表数字 v-bind的引号里会被解析为js表达式 -->
<c-button></c-button>
<!-- 注意一定要使用烤串命名法,否则会报错 -->
</div>
//定义一个组件
Vue.component('c-dialog',{
//Prop验证
props:{
title:{
type:String,
default:'标题'
},
//num可以是字符串,数字,数组类型
//num:[String,Number,Array],
//自定义验证规则
num:{
validator(value){
//value是外面num=""传进来的内容,验证传进来的内容是否合法
console.log(value);
return value>10; //自定义的条件,符合这个条件,验证成功,否则失败(报错)
}
},
confirmValue:{
type:String,
required:true //必填
},
list:{
type:Object,
//如果传递的类型是对象,其默认值default必须设置为函数,在这个函数里return默认的对象
default(){
return {}
}
}
},
//想要在content里定制一个ul列表
//想要把第二个弹框的footer的结构换成自己定制的结构:把footer的内容用slot包起来,给slot标签起一个名字,想用谁替换slot标签里的结构,就在谁的行间叫一下这个slot的名字
//批量替换:用template标签包起来,整体在template标签的行间叫一下这个slot的名字
/*
- slot标签放在哪,就会把组件的标签对之间的结构全部放在哪(注意:行间有slot属性的结构除外!!)
- 如果没有slot标签,组件标签对之间的结构就会丢弃
- 在 <slot> 标签中的任何内容都被视为备用内容:
- 如果在组件的`<content></content>`标签对里里放入`<slot>1111111<slot>`,1111111就是备用内容
- 如果没有在组件的标签对里写内容,就默认是1111111
*/
template:`
<div class="dialog">
<h2>{{title}}</h2>
<span>{{num}}</span>
<div class="content">
我是内容 //不会被定制的结构覆盖
<slot>1111111111111111111111</slot>
</div>
<div class="footer">
<slot name="footer-slot">
<button @click="confirmHandle">{{confirmValue}}</button>
<button>取消</button>
</slot>
</div>
</div>
`,
methods:{
confirmHandle(){
this.$emit('confirm');
}
}
});
Vue.component('c-button',{
template:`
<div>
<button>测试弹框</button>
<div ref="div2">控制我的颜色</div>
<c-dialog confirm-value="ok" @confirm = "confirmFn2">
<table>
<tr>
<th>姓名</th>
<th>姓名</th>
<th>姓名</th>
<th>姓名</th>
</tr>
</table>
<p slot="footer-slot">我是第二个定制的content结构</p>
<template slot="footer-slot">
<span>我是按钮</span>
<span>我是按钮</span>
<span>我是按钮</span>
<span>我是按钮</span>
</template>
</c-dialog>
</div>
`,
methods:{
confirmFn2(){
this.$refs.div2.style.background="green";
}
}
});
new Vue({
el:'#box',
methods:{
//想要隐藏的div是全局的div,不再c-dialog组件里,所以要通过父组件操作
confirmFn1(){
this.$refs.div1.style.display = 'none';
}
}
});
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。