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实现的也只是简单的功能。

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

  最后感谢大家的支持!

相关文章
|
6天前
|
缓存 JavaScript UED
Vue 中实现组件的懒加载
【10月更文挑战第23天】组件的懒加载是 Vue 应用中提高性能的重要手段之一。通过合理运用动态导入、路由配置等方式,可以实现组件的按需加载,减少资源浪费,提高应用的响应速度和用户体验。在实际应用中,需要根据具体情况选择合适的懒加载方式,并结合性能优化的其他措施,以打造更高效、更优质的 Vue 应用。
|
6天前
|
JavaScript
如何在 Vue 中使用具名插槽
【10月更文挑战第25天】通过使用具名插槽,你可以更好地组织和定制组件的模板结构,使组件更具灵活性和可复用性。同时,具名插槽也有助于提高代码的可读性和可维护性。
13 2
|
6天前
|
JavaScript
Vue 中的插槽
【10月更文挑战第25天】插槽的使用可以大大提高组件的复用性和灵活性,使你能够根据具体需求在组件中插入不同的内容,同时保持组件的结构和样式的一致性。
11 2
|
6天前
|
前端开发 JavaScript 容器
在 vite+vue 中使用@originjs/vite-plugin-federation 模块联邦
【10月更文挑战第25天】模块联邦是一种强大的技术,它允许将不同的微前端模块组合在一起,形成一个统一的应用。在 vite+vue 项目中,使用@originjs/vite-plugin-federation 模块联邦可以实现高效的模块共享和组合。通过本文的介绍,相信你已经了解了如何在 vite+vue 项目中使用@originjs/vite-plugin-federation 模块联邦,包括安装、配置和使用等方面。在实际开发中,你可以根据自己的需求和项目的特点,灵活地使用模块联邦,提高项目的可维护性和扩展性。
|
7天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
10天前
|
JavaScript
Vue 指令速查表
【10月更文挑战第12天】Vue 指令速查表
|
7天前
|
缓存 JavaScript 搜索推荐
Vue SSR(服务端渲染)预渲染的工作原理
【10月更文挑战第23天】Vue SSR 预渲染通过一系列复杂的步骤和机制,实现了在服务器端生成静态 HTML 页面的目标。它为提升 Vue 应用的性能、SEO 效果以及用户体验提供了有力的支持。随着技术的不断发展,Vue SSR 预渲染技术也将不断完善和创新,以适应不断变化的互联网环境和用户需求。
27 9
|
6天前
|
JavaScript 前端开发 UED
vue 提高 tree shaking 的效果
【10月更文挑战第23天】提高 Vue 中 Tree shaking 的效果需要综合考虑多个因素,包括模块的导出和引用方式、打包工具配置、代码结构等。通过不断地优化和调整,可以最大限度地发挥 Tree shaking 的优势,为 Vue 项目带来更好的性能和用户体验。
|
10天前
|
JavaScript 前端开发 开发者
Vue 的优缺点
【10月更文挑战第16天】Vue 具有众多优点,使其成为前端开发中备受青睐的框架之一。尽管它也存在一些局限性,但通过合理的应用和技术选型,这些问题可以得到一定程度的解决。在实际项目中,开发者可以根据项目的需求和特点,权衡 Vue 的优缺点,选择最适合的技术方案。同时,随着 Vue 不断的发展和完善,相信它将在前端开发领域继续发挥重要作用。
19 6
|
11天前
|
JavaScript 前端开发 编译器
在 Vue 项目中使用 ES 模块格式的优点
【10月更文挑战第20天】在 Vue 项目中使用 ES 模块格式具有众多优点,这些优点共同作用,使得项目能够更高效、更可靠地开发和运行。当然,在实际应用中,还需要根据项目的具体情况和需求进行合理的选择和配置。
20 6