目录
封装radio组件
radio.vue里初步模版:
<template>
<label class="miao-radio" >
<span class="miao-radio_input">
<span class="miao-radio_inner"></span>
<input type="radio" class="miao-radio_original">
</span>
<span class="miao-radio_label" type="radio">
我说label
</span>
</label>
</template>
<style lang="scss" scoped>
.miao-radio {
color: #606266;
font-weight: 500;
line-height: 1;
position: relative;
cursor: pointer;
display: inline-block;
white-space: nowrap;
outline: none;
font-size: 14px;
margin-right: 30px;
-moz-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
.miao-radio_input {
white-space: nowrap;
cursor: pointer;
outline: none;
display: inline-block;
line-height: 1;
position: relative;
vertical-align: middle;
.miao-radio_inner {
border: 1px solid #dcdfe6;
border-radius: 100%;
width: 14px;
height: 14px;
background-color: #fff;
position: relative;
cursor: pointer;
display: inline-block;
box-sizing: border-box;
&:after {
width: 4px;
height: 4px;
border-radius: 100%;
background-color: #fff;
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) scale(0);
transition: transform .15s ease-in;
}
}
.miao-radio_original {
opacity: 0;
outline: none;
position: absolute;
z-index: -1;
top: 0;
left: 0px;
right: 0;
bottom: 0;
margin: 0;
}
}
.miao-radio_label {
font-size: 14px;
padding-left: 10px;
;
}
}
// 选中的样式
.miao-radio.is-checked {
.miao-radio_input {
.miao-radio_inner {
border-color: #409eff;
background-color: #409eff;
&:after {
transform: translate(-50%, -50%) scale(1);
}
}
}
.miao-radio_label {
color: #409eff;
}
}
</style>
先把input_radio隐藏
首先设置v-model,name,label属性,需要传参数,
在radio.vue里设置:
label:{
type:[String, Number, Boolean],
default:''
},
value:null,
// v-model给什么无所谓,最终需要得到的是label的值,有v-model肯定会接收到value
// 作为表单元素可能传name
name:{
type:String,
default:''
},
v-model给什么无所谓,最终需要得到的是label的值,有v-model肯定会接收到value
app.vue里
<miao-radio label="1" v-model="gender">男</miao-radio>
<!-- 用来指定radio的值 -->
<miao-radio label="0" v-model="gender">女</miao-radio>
在radio.vue里肯定不能写固定的,用插槽替代,让男和女两个出现在界面里
如果没写字,一般会把label内容显示
<template v-if="!$slots.default">{{ label }}</template>
由于父组件传入数据不能修改,在radio里绑定的v-model绑定的数据应该是重写定义的
但是该数据取决于外部传入的value值还得能修改这个数据
通过计算属性:
computed: {
model: {
get(){
return this.value
},
set(value){
//触发父组件给当前组件注册的input事件
this.$emit('input',value)
}
}
}
修改template里第一句增加动态类
<label class="miao-radio" :class="{'is-checked': label===value}">
封装单选框组radio-group
这样不用给每个radio绑定变量
this.$parent找到组件的父组件,找到他找到value值从而触发input事件
但是有风险--
引出provide与inject:祖先给子孙组件依赖
在父组件用provide提供一个值,在任何孙组件里用inject获取值
radio-group.vue里:
provide(){
//提供一个对象
return {
RadioGroup: this
}
这是把自己提供出去了
radio.vue里:
inject:{
RadioGroup
},
能拿到group就能访问他的值
然后发现被radiogroup包裹的不能获取值,因为可能从radiogroup.value里获取
因此修改computed为:
computed: {
model: {
get() {
return this.iGroup? this.RadioGroup.value : this.value
},
set(value) {
this.iGroup ? this.RadioGroup.$emit('input', value) : this.$emit('input', value)
}
},
iGroup(){
//用于判断radio是否被radio group包裹,两个感叹号表示改成布尔值
return !!this.RadioGroup
}
}
最后修改radio.vue里:
<label class="miao-radio" :class="{'is-checked': label===model}">
封装checkbox组件和checkbox-group组件
首先checkbox里同radio:
<slot></slot>
<template v-if="!$slots.default">{{ label }}</template>
没值显示label
同样传参数:
value: {
type: Boolean,
default: false
},
label: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
同样通过provide和inject孙子和祖先通信:
可以把inject理解为加强版的props,不仅能接受父组件还能接受爷爷组件
checkbox.vue里:
inject: {
CheckboxGroup: {
default: ''
}
},
checkbox-group.vue里
provide () {
return {
CheckboxGroup: this
}
},
不同点在于,如果在checkbox-group里说明多个checkbox,则需要指明传参是数组:
props: {
value: {
type: Array
}
}
同radio和radiogroup一样,添加计算属性
model: {
get () {
return this.isGroup ? this.CheckboxGroup.value : this.value
},
set (value) {
this.isGroup ? this.CheckboxGroup.$emit('input', value) : this.$emit('input', value)
console.log(value)
}
},
isGroup () {
return !!this.CheckboxGroup
},
如果是多个box一起用,value就有用了,因为选中的是value,这个value就是label
checkbox.vue里,新添加value="label"
<span class="miao-checkbox_input">
<span class="miao-checkbox_inner"></span>
<input type="checkbox"
class="miao-checkbox_original"
:name="name"
v-model="model"
value="label"
>
</span>
有group时候有value="label"
然后还缺一个选中状态
ischecked() {
//如果是group包裹,判断label是否在model中
//如果没有group包裹,直接使用modle
return this.isgroup ? this.model.includes(this.label) : this.model
}
模版里更换为:
<label class="miao-checkbox" :class="{'is-checked':ischecked}">
form组件和form-item组件
通过form和form-item两个组件将前面的组件包起来:
form.vue:
<template>
<div class="miao-form">
<slot></slot>
</div>
</template>
<script>
export default {
name:'miaoForm',
props:{
model: {
type: Object,
required:true
// 用form必须传入model
}
}
}
form-item.vue:
<template>
<div class="miao-form-item">
<label class="miao-form-item_label">{{ label }}</label>
<div class="miao-form-item_content">
<slot></slot>
</div>
</div>
</template>
app.vue
<template>
<div id="app">
<miao-form :model="model">
<!-- :model用来收集所有的值 -->
<miao-form-item label="用户名">
<miao-input placeholder="请输入用户名" v-model="model.username"></miao-input>
</miao-form-item>
<miao-form-item label="选择">
<miao-switch v-model="model.active"></miao-switch>
</miao-form-item>
</miao-form>
</div>
</template>
将form组件传下去:
provide (){
return {
Form:this
}
}
接受form:
<label class="miao-form-item_label" :style="{width: this.Form.labelWidth}">{{ label }}</label>
inject:['Form']
具体代码详见: