Vue组件库开发—input区间输入组件

最近闲来无事,接了个组件库开发的活,在这里先记录一下~
!!! 写作不易,如要转裁,请标明转载出处。
本文借鉴于element-ui组件库的源码

1. 项目结构

可以去 github 自行下载 element-ui 源码,以下是新建组件的步骤简介,只想看 区间输入框 实现的同鞋可以自行跳过~

1.1 新建组件文件

packages下新建 range-input 文件夹,在其下面新建 index.js

import RangeInput from './src/range-input.vue';
RangeInput.install = function (Vue) {
  Vue.component(RangeInput.name, RangeInput);
}
export default RangeInput;
1.2 新建组件 vue

packages -> range-input -> src -> range-input.vue
具体的组件逻辑代码都是在这里写的!!!

1.3 引入组件

src -> index.js

1.4 新建md说明文档

examples -> components ->dosc -> range-input.md

1.5 新建文档文件

examples -> components ->views\components-> range-input.vue
在文件中引入步骤4的文档文件,控制说明文档的样式也可以写在这里~

<template>
  <div class="wrapper">
    <demo></demo>
  </div>
</template>
<script>
import demo from 'examples/components/docs/range-input.md'
export default {
  components: {
    demo
  }
}
</script>
1.6 在菜单中加新组建的路由

examples -> router ->menu.js


2. 区间输入框组件

2.1 区间输入框效果图
区间输入框效果图
2.2 调用实例

由下面的使用组件实例来看,双向绑定了变量 moneyData 为数组格式,数组中第一个元素为区间输入的起始值,数组中的第二个元素为区间输入的结束值。

<range-input
    type="money"
    placeholder="请输入金额"
    clearable
    v-model="moneyData"
    @input="moneyInput"
    @focus="moneyFocus"
    @blur="moneyBlur"
    @change="moneyChange">
</range-input>
2.3 组件编码
<template>
    <div class="range-input"
        :class="{'disabled': disabled}"
        :style="styleName"
        @mouseover="handleMouseover"
        @mouseout="handleMouseout">
        <div class="range-input-box"
            :class="{'active': rangeInputFocus, 'error': svgType == 'error'}">
            <div class="input-box">
                <input type="text"
                    class="range-input"
                    :disabled="disabled"
                    :placeholder="placeholder"
                    v-model="rangeInputs[0]"
                    @input="handleInput"
                    @focus="handleFocus"
                    @blur="handleBlur"
                    @change="handleChange">
            </div>
            <div class="range-input-divider"></div>
            <div class="input-box">
                <input type="text"
                    class="range-input"
                    :disabled="disabled"
                    :placeholder="placeholder"
                    v-model="rangeInputs[1]"
                    @input="handleInput"
                    @focus="handleFocus"
                    @blur="handleBlur"
                    @change="handleChange">
            </div>
            <svg class="svgClass"
                @click="svgType == 'del' && handleClear()"></svg>
        </div>
    </div>
</template>
2.4 方法编码

props中的是暴露出去的参数

<script>
export default {
    name: 'RangeInput',
    props: {
        type: { // 类型 便于表单验证 区间是只能输入钱数 还是整数等
            type: String,
            default:'input'
        },
        width: { // 组件的宽度
            type: String,
            default: '256px'
        },
        placeholder: { // 输入框占位文本
            type: String,
            default: ''
        },
        value: { // 绑定值
            type: Array,
            default: []
        },
        clearable: { // 是否支持清空
            type: Boolean,
            default: false
        },
        disabled: { // 是否禁用
            type: Boolean,
            default: false
        }
    },
    data () {
        return {
            svgClass: '',
            rangeInputFocus: false,
            rangeInputs: [...this.value],
            svgType: this.type,
            validateState: true, // 表单验证结果
            errorMessage: '',
        }
    },
    computed: {
        styleName () {
            return {
                width: this.width
            }
        },
        svgName () {
            return this.svgType == 'money' ? '#svg_sales' : 
                   this.svgType == 'del' ? '#svg_close' : '#svg_draw'
        }
    },
    methods: {
        handleInput () {
            this.$emit('input', [...this.rangeInputs]);
        },
        handleFocus (event) {
            this.rangeInputFocus = true;
            this.$emit('focus', event);
        },
        handleBlur (event) {
            this.rangeInputFocus = false;
            this.$emit('blur', event);
        },
        handleChange () {
            this.$emit('change', [...this.rangeInputs]);
        },
        hanleMouseover () {
            if (!this.validateState) {
                this.svgType = 'error';
            } else {
                this.rangeInputs && this.rangeInputs.length && this.clearable ? this.svgType = 'del' : this.svgType = this.type;
            }
        },
        handleMouseout () {
            if (!this.validateState) {
                this.svgType = 'error';
            } else {
                this.svgType = this.type;
            }
        },
        handleClear () {
            this.rangeInputs = ['', ''];
            this.$emit('input', null);
        }
    }
};
</script>
2.5 样式编码
<style lang="scss" scoped>
%highlight {
    position: absolute;
    bottom: 0;
    left: 0;
    content: '';
    width: 100%;
    height: 1px;
}
.range-input{
    padding: 4px 0;
    .range-input-box{
        position: relative;
        display: flex;
        align-items: center;
        height: 32px;
        line-height: 32px;
        border-radius: 8px;
        background: $c129;
        overflow: hidden;
        &.active:after{
            @extend %hightlight;
            background: $a001;
        }
        &.error:after{
            @extend %hightlight;
            background: $c001;
        }
        .input-box{
            width: calc((100% - 6px - 18px -6px) / 2);
            .range-input{
                width: 100%;
                padding: 0 6px 0 8px;
                @include body1;
                height: 32px;
                line-height: 32px;
                box-sizing: border-box;
                background: transparent;
                color: $c121;
                &::-webkit-input-placeholder{
                    color: $c125;
                }
                &::-moz-placeholder{
                    color: $c125;
                }
            }
        }
        .range-input-divider{
            content: '';
            width: 6px;
            height: 1px;
            background: $c126;
        }
    }
    &:hover{
        .range-input-box{
            background: $c128;
        }
    }
    &.disabled{
        .range-input-box{
            cursor: not-allowed;
            background: $c130;
        }
    }
}
</style>

第一次参与组件库的研发与制作,在实现上肯定存在不足的地方,欢迎大家来评论区里留言,感谢大家的批评与指正~
如果本文对你有所帮助,感谢点一颗小心心,您的支持是我继续创作的动力!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容