零、先思考

大家可以想想element里的组件像<el-input /> 数据绑定是怎么做的,怎么绑定v-model就可以改变父组件的值呢?

一、食用前甜品

v-model是input+value的语法糖。怎么说?其实

<your-component v-model='yourData'>

等价于

<your-component :value='yourData' @input='val => yourData = val'>

所以别人在父组件用你封装好的话,父组件就不用再定义一个子传父的方法val => yourData = val,太麻烦了,然后子组件$emit(‘input’,…)…

v-model直接tm给你合并了,这样,你封装好的组件给别人用就方便多了,提高组件封装性

二、献上效果图展示 此组件有需要的同学可以直接复制使用在这里插入图片描述

三、子组件 timerPickLimit.vue

<!--
@name: 24 * 7时间选择器
@description: 主要作用于设备禁止登录时间选择
@Method: 使用v-model改进 等价<timer-pick-limit :value="formData.loginLimit" @input="val => forData.loginLimit = val"/>
<timer-pick-limit v-model="formData.loginLimit" />
@author: winsonZheng
@time: 2021/2/23
-->
<template>
    <div class="field">
        <div id="time" class="cell-selector-wrap sub-form">
            <table class="cell-selector">
                <thead>
                <tr>
                    <th></th>
                    <th v-for="item in 24" :key="item">{{ item }}</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="(item,index) in week" :key="item">
                    <th>{{ item }}</th>
                    <td v-for="(_item,_index) in value[index]" :key="_index">
                        <div :style="{backgroundColor:_item===1?pickColor:'#fff'}" @click="changePickStatus($event,index,_index)"></div>
                    </td>
                </tr>
                </tbody>
            </table>
            <div class="caption">
                <div class="caption-item"><span class="checked"></span>允许</div>
                <div class="caption-item"><span class="normal"></span>禁止</div>
            </div>
        </div>
    </div>
</template>
<script lang="ts">
import {Component, Prop} from 'vue-property-decorator';
import Vue from 'vue'
import _ from 'lodash'

interface FormData {
    loginLimit: Array<Array<number>>
    // PS:数据结构,长这样
    //loginLimit: [
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        ]
}

@Component
export default class extends Vue {
    @Prop()
    value: FormData //此处一定是value,v-model默认

    private formDataCopy = {}
    private pickColor = 'rgb(86, 161, 232)';
    private week = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];

    //TODO 日期选择模块
    private changePickStatus(e, index, _index) {
        this.formDataCopy = _.cloneDeep(this.value)
        if (this.formDataCopy[index][_index] === 1) {
            this.formDataCopy[index][_index] = 0;
            //此处emit input , v-model默认值
            this.$emit('input', this.formDataCopy)
            e.target.style.backgroundColor = '#fff'
        } else {
            this.formDataCopy[index][_index] = 1;
            this.$emit('input', this.formDataCopy)
            e.target.style.backgroundColor = this.pickColor
        }
    }

}
</script>
<style lang="scss" scoped>
.text-area {
    p {
        line-height: 1.5;
        color: #999999;
        margin: 10px 0 0 0;
        text-align: justify;

    }
}

.cell-selector {
    tbody tr {
        th {
            width: 50px;
        }

        td {
            width: 30px;
        }

        div {
            width: 100%;
            height: 33px;
        }

        div.on {
            background-color: #56a1e8;
        }
    }
}

.caption {
    display: flex;
    margin-top: 10px;

    .caption-item {
        width: 30px;
        height: 30px;
        background: #56a1e8;
        color: #fff;
        margin-right: 20px;
        padding: 2px 10px;
    }

    > :last-child {
        margin-right: 0;
        background: #fff;
        color: #1a1a1a;
        border: 1px solid #DCDFE6
    }
}
</style>

四、父组件 index.vue 引用子组件

<timer-pick-limit v-model="formData.loginLimit" />

使用v-model改进 等价

<timer-pick-limit :value="formData.loginLimit" @input="val => forData.loginLimit = val"/>
Logo

前往低代码交流专区

更多推荐