美文网首页
vue实现复杂的表单Dom操作

vue实现复杂的表单Dom操作

作者: 毕竟1米八 | 来源:发表于2023-02-15 22:40 被阅读0次

    春节过后公司需要上线一个抽奖优惠活动,在后台管理页面中涉及到表单的动态添加、修改dom等复杂操作。开发的过程中遇到许多的知识点和困难点,于是总结了以下一些技巧经验。

    一、业务需求

    如图所示,在抽奖页面中,涉及到获取奖品、添加奖品、修改奖品、删除奖品(增删改查)、上传图片等功能。

    • 奖品类型分别是租期、实物、谢谢惠顾。谢谢惠顾类型由后台返回,不可添加只能修改,且类型不能修改,只能修改奖品名称和中奖概率和奖品展示。
    • 租期类型没有图片字段、实物类型没有天数字段。
    • 每一列上传图片功能。
    • 当对当前列的数据进行修改时,按钮文案从修改变成保存,并且显示不同的按钮背景颜色。
    • 删除数据时要区分dom数据还是服务端返回的真实数据,前者则不需要调用删除接口。

    二、vue版本
    基于vue2.x语法和element-ui框架。

    三、难点分析

    • 如何区分前端追加的dom数据和服务端返回的真实数据?(即添加和修改的区别)
    • 每一列的表单编辑中状态如何实现?(修改按钮-->保存按钮)

    四、关键代码实现

    // data数据
    lotteryList: [
                    // {
                    //     hl_name: "",
                    //     hl_type: null,
                    //     hl_days: "",                                                                                                                                                    
                    //     hl_lnums: "", //库存
                    //     hl_shownum: "", //展示数量
                    //     hl_img: "",
                    //     isImgUpload: false, // 上传图片开关 前端加的判断
                    //     isEdit: false, // 是否编辑状态 前端加的判断
                    //     hl_lucky: true, // 1开 2关 提交的时候需要转换一下
                    //     hl_rate: "", // 概率
                    // },
                ],
                watchLotteryList: [], // 用来监听列表的数据变化
                originLotteryList: [],  // 源数据 深拷贝后的
                curIndex: null
    
    
    // 动态添加dom
    onAdd() {
                // 默认追加的dom数据是没有id的 因此根据id来区别真假数据
                this.lotteryList.push({
                    hl_name: "",
                    hl_type: null,
                    hl_days: "",
                    hl_lnums: "",
                    hl_shownum: "",
                    hl_img: "",
                    isImgUpload: false, // 前端加的判断
                    isEdit: false, // 前端加的判断
                    hl_lucky: true,
                    hl_rate: "",
                });
            },
    
    // 获取抽奖列表
            getList() {
                getLottery({}).then(res => {
                    console.log('res: ', res);
                    if(res.state == 0){
                        if (res.data) {
                            let data = res.data
                            data.filter(item => {
                                item.hl_type = Number(item.hl_type)  // 需要number类型 否则el-select不会回显
                                item.hl_lucky = item.hl_lucky == 1 ? true : false;
                                item.isEdit = false // 追加一个编辑状态
                            })
                            console.log('data: ', data);
                            this.lotteryList = data
                            
                            // this.watchLotteryList = JSON.parse(JSON.stringify(data))
                            // 保持一份初始数据 不被双向绑定给影响到
                            this.originLotteryList = JSON.parse(JSON.stringify(data))
                            // 这一份数据用来监听列表数据的 因为直接监听lotteryList再修改原数据lotteryList会造成监听无限执行
                            this.watchLotteryList = data
                        } else {
                            this.lotteryList = []
                        }
                    }
                })
            },
    
    // 删除
    onDelete(index) {
               if (this.lotteryList[index].hl_id) {
                   // 真实数据
                   console.log('真实数据: ');
                   delLottery({
                       hl_id: this.lotteryList[index].hl_id
                   }).then(res => {
                       if (res.state == 0) {
                           this.$message({
                               message: '删除成功',
                               type: 'success'
                           });
                           this.getList()
                       }
                   })
               } else {
                   // dom数据
                   console.log('dom数据: ');
                   this.lotteryList.splice(index, 1);
               }
           },
    
    watch: {
            // lotteryList: {
            // 不要监听列表用的lotteryList数据 因为最终要修改lotteryList数据 会造成监听无限执行
            watchLotteryList: {
                // 深度监听会造成val和oldVal的值相同
                handler(val, oldVal) {
                    setTimeout(() => {
                        console.log('---', this.curIndex, this.lotteryList[this.curIndex])
                        // 存在id 即编辑状态下
                        if (this.curIndex !=null && this.lotteryList[this.curIndex].hl_id) {
                                console.log('originLotteryList: ', this.originLotteryList[this.curIndex]);
                                console.log('val: ', val[this.curIndex]);
                                if (this.isEqual(this.originLotteryList[this.curIndex], val[this.curIndex])) {
                                    console.log('2个对象数据一致')
                                    this.lotteryList[this.curIndex].isEdit = false
                                    // 原始数据也要同步修改
                                    this.originLotteryList[this.curIndex].isEdit = false
                                } else {
                                    console.log('2个对象数据不一致!!!')
                                    this.lotteryList[this.curIndex].isEdit = true
                                    this.originLotteryList[this.curIndex].isEdit = true
                                }
                                console.log('最后', this.lotteryList[this.curIndex])
                                // this.curIndex = null
                        }
                    }, 50)
                },
                deep: true
            },
        },
    
    // 记录当前选中的数据 select则用@change事件 其他元素添加@click事件
            onItem(index) {
                console.log('选中下标', index)
                this.curIndex = index
            },
    
    // 对比2个对象是否一致
            isEqual(objA, objB){
                //相等
                if(objA === objB) return objA !== 0 || 1/objA === 1/objB;
                //空判断
                if(objA == null || objB == null) return objA === objB;
                //类型判断
                if(Object.prototype.toString.call(objA) !== Object.prototype.toString.call(objB)) return false;
    
                switch(Object.prototype.toString.call(objA)){
                    case '[object RegExp]':
                    case '[object String]':
                        //字符串转换比较
                        return '' + objA ==='' + objB;
                    case '[object Number]':
                        //数字转换比较,判断是否为NaN
                        if(+objA !== +objA){
                            return +objB !== +objB;
                        }
    
                        return +objA === 0?1/ +objA === 1/objB : +objA === +objB;
                    case '[object Date]':
                    case '[object Boolean]':
                        return +objA === +objB;
                    case '[object Array]':
                        //判断数组
                        for(let i = 0; i < objA.length; i++){
                            if (!this.isEqual(objA[i],objB[i])) return false;
                        }
                        return true;
                    case '[object Object]':
                        //判断对象
                        let keys = Object.keys(objA);
                        for(let i = 0; i < keys.length; i++){
                            if (!this.isEqual(objA[keys[i]],objB[keys[i]])) return false;
                        }
    
                        keys = Object.keys(objB);
                        for(let i = 0; i < keys.length; i++){
                            if (!this.isEqual(objA[keys[i]],objB[keys[i]])) return false;
                        }
    
                        return true;
                    default :
                        return false;
                }
            },
    
    // 防抖函数
            debounce(func, wait = 300, timer, immediate = false) {
                //  移除定时器
                if (timer !== null) {
                    clearTimeout(timer)
                }
                //  是否立即执行
                if (immediate) {
                    //  立即执行
                    const callNow = !timer
                    timer = setTimeout(() => {
                        timer = null
                    }, wait)
                    if (callNow) typeof func === 'function' && func()
                } else {
                    //  设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
                    timer = setTimeout(() => {
                    typeof func === 'function' && func()
                    }, wait)
                }
            },
    

    相关文章

      网友评论

          本文标题:vue实现复杂的表单Dom操作

          本文链接:https://www.haomeiwen.com/subject/vmeukdtx.html