外星人源码论坛 首页 编程经验 Vue组件 - 智能联想输入框

Vue组件 - 智能联想输入框

2018-3-5 06:52
原作者: 外星人源码网 来自: 外星人源码网 收藏 分享 邀请

已经有很多成熟的智能输入框组件,如Form.js。但是现在MVVM框架,如vue、react的为了实现双向数据绑定会重绘所有的元素,这样就会难以兼容使用。所以笔者开发了Vue组件-智能输入框。 包含的功能大同小异:获得焦点时 ...

已经有很多成熟的智能输入框组件,如Form.js。但是现在MVVM框架,如vue、react的为了实现双向数据绑定会重绘所有的元素,这样就会难以兼容使用。所以笔者开发了Vue组件-智能输入框。

包含的功能大同小异:

    获得焦点时显示所有备选项 失去焦点时隐藏备选项面板 输入字符后,检索可能的备选项 支持上下键和回车键进行选中 支持点击选中 支持多选 以逗号进行多选的分割

效果图:

// 源码
// 给数组添加原型方法:循环计数。
// 输入环的长度,一个数字(可为负,可选)。返回合适的位置
Object.defineProperty(Number.prototype, 'circlePlus', {value: function (length, count = 1) {
    return (this + count % length + length) % length;
}});

Vue.component('smart-input', {
        template: `<div>
            <input v-model="input"
                placeholder="输入文本自动检索,上下键选取,回车选中,可点选"
                data-toggle="tooltip"
                @focus="init" @keyup="search" @blur="blur" />
            <ul v-show="searching">
                <li v-for="(item, index) in filtered" :class="{active: focusIndex===index}" @click.stop="clickOne">{{ item }}</li>
            </ul>
            <div v-show="searching" @click="searching=false"></div>
        </div>`,
        props: ['list', 'multiple', 'value'],
        data() {
            return {
                searching: false,
                timer: null,
                filtered: {},
                input: '',
                focusIndex: 0,
                invalidData: '',
            };
        },
        computed: {
            listLength() {
                return this.filtered.length;
            },
            key() {
                return /(?:.*,)*(.*)$/.exec(this.input)[1];
            }
        },
        methods: {
            // 调整联想搜索面板的大小和位置
            init(e) {
                this.searching = true;
                this.filtered = this.list;
            },
            // 失去焦点时关闭面板,主要是按下tab键切换时的作用,随之带来的是所有相关的事件都要清除该定时器
            blur() {
                this.timer = setTimeout(() => {
                    this.searching = false;
                }, 200);
            },
            // 联想搜索的主体功能函数
            search(e) {
                e = e || window.event;
                // clearTimeout(this.timer);
                // 通过上下键和回车选择
                if (e.keyCode === 38) {
                    this.focusIndex = this.focusIndex.circlePlus(this.listLength);
                    // $('.friendSearch').scrollTop($(selectee).index(selected) * 26 - 26);
                } else if (e.keyCode === 40) {
                    this.focusIndex = this.focusIndex.circlePlus(this.listLength, -1);
                } else if (e.keyCode === 13) {
                    this.selectOne();
                } else {
                    // 进行可选项过滤
                    this.filtered = this.list.filter((item) => {
                        return item.toLowerCase().includes(this.key.toLowerCase());
                    });
                }
            },
            clickOne(e) {
                clearTimeout(this.timer);
                e = e || window.event;
                let value = $(e.target).text();
                if (this.multiple) {
                    let arr = this.input.split(',');
                    arr.splice(arr.length, 1, value);
                    this.input = arr.join(',') + ',';
                } else {
                    this.input = value;
                }
                $('input', $(this.$el)).focus();
            },
            // 选择一个参数
            selectOne(e) {
                let value = this.filtered[this.focusIndex];
                if (this.multiple) {
                    let arr = this.input.split(',');
                    arr.splice(arr.length, 1, value);
                    this.input = arr.join(',') + ',';
                } else {
                    this.input = value;
                }
            },
        },
        watch: {
            value(val) {
                this.input = val;
            },
            input(val) {
                let inputArr = val.split(',');
                if (this.multiple) {
                    inputArr.pop();
                    let invalidData = [];
                    inputArr.forEach(item => {
                        if (!this.list.includes(item)) {
                            invalidData.push(item);
                        }
                    });
                    let $input = $('input', $(this.$el));
                    if (invalidData.length) {
                        $input.attr('title', invalidData.join(',') + '数据不合法');
                        $input.tooltip();
                    } else {
                        $input.tooltip('hide');
                    }
                }
                this.$emit('sync', this.input);
            },
        }
    });

使用方式:

    注册全局组件Vue.component 建立new Vue({el: #root})新对象 在root根组件里直接添加<smart-input>标签
// syncValueType是从子组件同步内容到父组件的函数,定义在父组件内
// valueTypeList是父组件向子组件传递的用于智能输入的数组
<smart-input @sync="syncValueType" :list="valueTypeList"></smart-input>

后续需要完善的功能:

    支持自定义分割符,添加参数delimiter: '-' 支持数据校验(不合法的不允许输入),添加参数stric: true 完善接口文档和补充在线测试用例

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

粉丝 阅读89 回复0
推荐资讯
国内最专业的源码技术交流社区
全国免费热线电话

0373-5171417

周一至周日9:00-23:00

反馈建议

admin@eenot.com 在线QQ咨询

扫描二维码关注我们