Vue组件入门篇 —— 表单组件(三)

简介: 做项目的时候会遇到一个比较头疼的问题,一个大表单里面有好多控件,一个一个做设置太麻烦,更头疼的是,需求还总在变化,一会多选、一会单选、一会下拉的,变来变去的烦死宝宝了。

文本框类的表单元素组件

  说了这么多,还没看到代码,是不是等不急了呢?其实代码也没啥好说的,就是用了最笨的方法,一点一点设置属性。

Vue.component('my-input', {
    props:["value","meta"],
    data:function(){
        return {
            type:{  //把编号变成文本的形式
            100:'textarea',         //多行文本框
            101:'text',             //单行文本框
            102:'password',         //密码
            103:'date',             //日期
            //其他略。。。。。。
            }
        }
     },
    methods:{
        //text
        textInput:function(event, meta){
            var returnValue = event.target.value;
            //添加自己的监听事件。本来想写在一起的,但是不好用,只好分开了。
            //vue的回调
            this.$emit('input',returnValue);
        },
        textChange:function(event, meta){
            var returnValue = event.target.value;
            //添加自己的监听事件
            this.$emit('change', returnValue,event.target, meta);
        }
    },
    template: `<span>
        <span v-if="meta.controlType===100">
            <!--多行文本框-->
            <textarea :id="'c'+meta.controlId" 
            :name="'c'+meta.controlId"  
            :class="meta.class" 
            :readonly="meta.readonly"
            :rows="meta.rows" 
            :cols="meta.cols" 
            @input="$emit('input',$event.target.value)"  
            @onkeyup="textChange($event,meta)"
            :placeholder="meta.placeholder"
            >
            </textarea>
        </span>
        <span v-else-if="meta.controlType>100 && meta.controlType<130 ">
            <!--文本框类-->
            <input  :id="'c'+meta.controlId" 
            :name="'c'+meta.controlId"  
            :disabled="meta.disabled"
            :class="meta.class" 
            :type="type[meta.controlType]" 
            :value="value" 
            :placeholder="meta.placeholder"
            :readonly="meta.readonly"
            :size="meta.size"
            :maxlength="meta.maxlength"
            :autocomplete="meta.autocomplete"
            :min="meta.min"
            :max="meta.max"
            :step="meta.step"
            :multiple="meta.multiple"
            :list="meta.listKey"
            :title="meta.title"
            @input="textInput($event,meta)"
            @change="textChange($event,meta)"
            :key="'ckey_'+meta.controlId">
            <!--文本框的备选项-->
            <datalist v-if="typeof(meta.listKey)!=='undefined'" :id="meta.listKey">
                <option v-for="item in meta.list" :label="item.id" :value="item.name" />
            </datalist>
        </span>
});


1、属性

  value用于双向绑定,这个要单独设置,其他的属性统统放在meta里面。这样接口就固定了,以后需要新的属性也不用修改接口。

2、内部变量
  这个是为了做个替换,因为外部设置的是类型编号,而不是类型名称,所以内部需要做一个替换,这样浏览器才能识别。

  那么为啥用编号,而不直接用浏览器支持的类型呢?因为有些类型要做两种用途,比如file上传文件和上传图片。两种方式要做个区分的,比如上传图片,可以做个图片预览,图片处理等功能,上传文件的话,就没有这些了。所以要做个编号加以区分。另外像多行文本框和下拉列表框用的不是input,没有type。

3、模板
  这里就很笨了,用v-if根据controlType做判断,是哪种控件就渲染对应的模板。然后把属性一一绑定上就可以了。

  然后就是事件的绑定。因为用户输入内容后,要通知上层调用者,所以需要加个事件返回用户输入值。第一个input是给Vue准备的,加上这个才能实现Vue的双向绑定。

  那么第二个事件是干啥的?有的时候我们自己需要知道用户的输入操作,依据输入做些操作,比如联动下拉列表框。我们要知道第一个下拉列表框的change,然后设置第二个下拉列表框。这个时候就需要我们自己的事件通知。一开始想在一个函数里通知两个上层事件的,但是没有成功。所以只好分开了。Emmm,也许可以改成数据驱动的方式,这个还没太想好。

4、方法
  写了两个方法,一个是返回给Vue的,实现数据双向绑定。另一个是给我们自己用的。

选择类的表单元素组件

  选择类指的是多选组(checkbox)、单选组(radio)、复选框(checkbox)以及下拉列表框。

Vue.component('my-input', {
    props:["value","meta"],
    methods:{
        //select
        selectChange:function(event, meta){
            var returnValue = '';
            var items = event.target.selectedOptions; //选中项的集合
            var arr = [];
            for (var i=0;i<items.length;i++) {
                var item = items[i];
                arr.push(item.value);
            }
            returnValue = arr.join(',');
            //添加联动事件
            this.$emit('select', returnValue, meta.nextSelect);
            //vue的回调
            this.$emit('input',returnValue);
            return returnValue;
        },
        //CheckBox
        checkChange: function (event) {
            var returnValue = event.target.value;
            if (this.meta.controlType === 155) {
                //复选框
                returnValue = event.target.checked;
            }
            else{
                //修改绑定情况
                var selectValue = returnValue;
                var arr = [];
                for (var key in this.meta.list) {
                    var item = this.meta.list[key];
                    if (item.id === selectValue) {
                        this.meta.list[key].check = event.target.checked;
                    }
                    if (item.check) {
                        arr.push(item.id);
                    }
                }
                returnValue = arr.join(',');
            }
            //调用上级的input事件
            this.$emit('input',returnValue);
            return  returnValue;
        },
        //radio
        radioChange: function (event, meta) {
            //单选
            var returnValue = '';
            var items = event.target.selectedOptions; //选中项的集合
            var arr = [];
            for (var i=0;i<items.length;i++) {
                var item = items[i];
                arr.push(item.id);
            }
            returnValue = arr.join(',');
            this.$emit('select', returnValue, meta.nextSelect);  //添加联动事件
            return returnValue;
        }
    },
    template: `<span>
        <span v-else-if="meta.controlType >= 150 && meta.controlType <= 152  ">
        <!--下拉列表框-->
            <select  :id="'c'+meta.controlId" 
            :name="'c'+meta.controlId"  
            :class="meta.class" 
            :multiple="meta.controlType === 151"
            @change="selectChange($event,meta)" 
            >
                <option :key="-2" value="-2" >请选择</option>
                <option
                 v-for="(item,index) in meta.list" 
                 :key="index"  
                 :value="item.id" 
                 :selected="item.check">
                    {{item.name}}
                </option>
            </select>
        </span>
        <span v-else-if="meta.controlType === 153 ">
            <!--单选组 -->
            <label role="radio" v-for="item in meta.list" >
                <input
                    type="radio" 
                    :class="meta.class"  
                    :checked="item.check" 
                    :name="'c'+meta.controlId" 
                    :value="item.id"
                    @input="$emit('input',$event.target.value)"  
                >
                <span>{{item.name}}</span>
            </label>
        </span>
        <span v-else-if="meta.controlType === 154 ">
            <!--多选组-->
            <label role="checkbox" 
            v-for="item in meta.list" 
            class="checkbox_g_t" 
            :key="'lblchks'+item.id"  >
                <input  :id="'c'+meta.controlId" 
                type="checkbox"
                :name="'c'+meta.controlId"  
                :class="meta.class" 
                :value="item.id"
                :readonly="meta.readonly"
                :key="'chks'+item.id"
                @input="checkChange($event)"
                >
                <span>{{item.name}}</span>
            </label>
        </span>
        <span v-else-if="meta.controlType === 155 ">
            <!--复选框-->
            <label role="checkbox" 
            v-for="item in meta.list" 
            class="checkbox_g_t" 
            :key="'lblchk'+item.id"  >
                <input  :id="'c'+meta.controlId" 
                type="checkbox"
                :name="'c'+meta.controlId"  
                :class="meta.class" 
                :value="item.id"
                :readonly="meta.readonly"
                :key="'chk'+item.id"
                @input="checkChange($event)"
                >
                <span>{{item.name}}</span>
            </label>
        </span>
    </span>`
});
  1. 模板
      还是老办法,用v-if判断渲染哪个模板,然后还是一个一个赋值,然后选项有一个循环,v-for一下就可以了。这里的选项格式和文本框的备选项格式采用了相同的设置。这样统一一下比较方便。
  2. 方法
      每类控件都做一个方法,对应不同的取值方式。不知道有没有更好的方式,现在用的比较麻烦,期待更好的方法。如果发现了肯定会更新的。


      还有个返回值类型的问题,我是习惯返回字符串的形式,比如1,2,3 。而不是数组。因为数据库里保存的是字符串而不是数组。当然这块应该能够灵活一些,打算加一个返回值类型的设置。

辅助工具

  这么复杂的json要怎么弄?不会告诉我要手撸吧!当然不是,我这么懒怎么能手写呢,当然是弄个工具来辅助了。

  辅助工具的思路,首先确定要哪种类型的表单元素,然后根据类型显示需要设置的属性,然后就可以点点点了(当然有些属性需要打几个字),就可以生成json文件,同时还可以预览效果。

  这个只是第一步哦,后面的还会有根据文档生成的辅助工具。

  文档在哪里?做项目总会有个数据库文档吧,文档会描述都有啥表,啥字段。会介绍一下字段名称、字段类型、字段大小吧。这样我们就可以根据这些信息设置默认的json了。然后不能默认的再点点点一下就可以了。

  这个辅助工具就是用的这个表单元素组件写的,也算是一个实际应用,代码比较多,就不贴了。感兴趣的话,看下面开源介绍。

23.jpg


开源

  源码下载:https://github.com/naturefwvue

  在线演示:https://naturefwvue.github.io/form/formHelp.html

  这里是表单元素组件源码和demo,还有那个辅助工具。

  另外会保持持续更新的,毕竟现在还只是初步学习vue实现的也只是简单的功能。

  下图是辅助工具的页面,首先选择类型,然后预留会有变化,然后按照下面的属性选择即可,同时预览也会有对应的变化。

  最后感谢大家的支持!

相关文章
|
7天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
51 1
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
148 64
|
17天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
41 8
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
48 1
vue学习第一章
|
2月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
34 1
|
2月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
41 1
vue学习第四章
|
2月前
|
JavaScript 前端开发 算法
vue学习第7章(循环)
欢迎来到瑞雨溪的博客,一名热爱JavaScript和Vue的大一学生。本文介绍了Vue中的v-for指令,包括遍历数组和对象、使用key以及数组的响应式方法等内容,并附有综合练习实例。关注我,将持续更新更多优质文章!🎉🎉🎉
32 1
vue学习第7章(循环)

热门文章

最新文章