vue2项目升级到vue3经历分享5

写到第5篇了,解决了很多问题,还有一些需要调整
1 el-input-number指令兼容性调整
下面这个可编辑的表格,全是0,于是需要一个指令,让它自己实现如果是0,就置空;如果是数字就是格式化为千分位;如果焦点放上去,变成数字。焦点失去有变成格式化。
1
在vue2中这么写,但在vue3中vnode.elm.querySelector,这种写法是不行的,因为你不应该直接操作dom,el 参数实际上指向的是 el-input-number 的根 DOM 元素,而不是内部的 input 元素。由于 el-input-number 是组件,不是原生的 input 元素,直接监听其内部 input 事件可能不太方便。

let options = {
  precision: 2,
  thousands: ','
}
const money = (el, binding, vnode) => {
  // // 判断是否是input元素
  if (vnode) {
    el = vnode.elm.querySelector('input')
  } else {
    throw new Error('v-money-format requires 1 input')
  }
  const opt = Object.assign({}, options, binding.value ? binding.value : {})
  const regStr = '/^$*+?.|'
  const inRegStr = regStr.includes(opt.thousands) ? (`\\${opt.thousands}`) : opt.thousands
  const thousandsReg = new RegExp(inRegStr, 'g')

  if (!el.isFocus) { //设置初始值 input框为0 去除显示
    if (el.value == 0) {
      el.value = '';
    }else if(el.value != '' || el.value != 0){  //初始化千分位
      el.value = el.value.replace(thousandsReg, '').cut();
    }
  }
  el.onfocus = function () {
    el.isFocus = true
    el.value = el.value.replace(thousandsReg, '')
  }
  el.onblur = function () {
    el.isFocus = false
    if (el.value != '') {
      el.value = el.value.cut();
    }
    if (el.value == 0) {
      el.value = '';
    }
    // el.value = moneyFormat(el.value, opt.precision, opt.thousands)
  }
  el.oninput = function () {
    el.value = el.value.replace(/[^\d.-]/g, '')
  }
}

export default money

把这个代码放到文心一言,改成vue3的模式,无效,只能自己想办法。调整为vue3的模式

/**
 * 金额格式化指令
 */
import $tool from '@/utils/tool'  
  
const options = {  
  precision: 2,  
  thousands: ','  
}  
  
const money = {  
  mounted(el, binding,vnode) {  
    let input;
    if (vnode){
      input = el.querySelector('input');
    } else{
      throw new Error('v-money-format requires 1 input');
    }

    const opt = Object.assign({}, options, binding.value || {})  
    const regStr = '/^$*+?.|'  
    const inRegStr = regStr.includes(opt.thousands) ? (`\\${opt.thousands}`) : opt.thousands  
    const thousandsReg = new RegExp(inRegStr, 'g')  
  
    // 初始化输入框
    if (!input.isFocus && input.value) {
      if (input.value === '0') {
        input.value = '';
      } else if (input.value !== '' || input.value !== '0') {
        let fmt = $tool.cut(input.value.replace(thousandsReg, ''));
        input.value = fmt
        console.log(input.value);
      }
    } else {
      input.value = null;
    }
    
    // 监听事件
    input.addEventListener('focus', () => {
      input.isFocus = true;
      input.value = input.value.replace(thousandsReg, '');
    });

    input.addEventListener('blur', () => {
      input.isFocus = false;
      if (input.value !== '') {
        input.value = $tool.cut(input.value);
      }
      if (input.value === '0') {
        input.value = '';
      }
    });


    input.addEventListener('input', () => {
      if (input.value) {
        input.value = input.value.replace(/[^\d.-]/g, '');
      } else {
        input.value = '0';
      }
    });

  },  
}  
  
export default money;

运行提示moneyFormat.ts:31 The specified value "3,333" cannot be parsed, or is out of range,
vue2是没有这个问题的,分析原因,在vue2中el-input-number类型依旧是text
1
但是在element-plus中变成了number,改成el-inpu,结果发现blur事件后input.value被置空了。搞了快一天了,项目进度要紧,这种方案放弃了。
2
如果不用指令,采用formatterparser会怎么样呢?
1
调试你会发现,如果是在表格中,你没改一下,整个数字样式都不会重新格式化一遍。虽然这样,但是可用。
2 v-model中默认属性的问题
在vue2中当你的组件采用v-model绑定值,例如
1
进入到组件中,通过this.value赋值,这个在vue3中是不行的,需要改成modelValue,否则undefined错误
1
还需要定义出来。
1
3 keep-alive有些页面缓存了,有些没有缓存
setup模式下,给页面定义一个名称,就可以被缓存。

defineOptions({
  name: "采购入库单"  
})

但是在本次vue2升级到vue3的过程中,发现有些页面增加后,缓存了,有些没有被缓存了。经过调试发现
1
上面的name中的内容,要跟页签的名称一致,否则不会缓存。也就是说,这个name必须设置为凭证字才可以。这么推理keepalive应该是map结构。
1
即你必须要改成与页签同名,因为这个页面名在项目中是Component的名称
1
4 el-check-group兼容性问题
el-check-group里面有一个el-checkbox问题,在element-ui中可以,但在element-plus中需要按照右边进行调整
1
5 el-image路径问题
vite中不支持require,直接将el-image改成img更方便
1
6 dom节点中代理类的问题
Vue 3 在内部实现响应式系统时采用了代理(Proxy)模式,因此下方节点中this.$tool的引用虽然在开发环境可以运行,但是运行到生产环境是会报错,找不到方法的。必须采用proxy.$tool,这样才能获取方案。
1
7 剩余参数异常跳出差异
this.virtualRows = [...child];,这个在webpack下面是可行的,但是在vite中是不可行的。因为在webpack中会自动编译为

_this5.virtualRows = Object(E_workspace_vuework_acc_web_node_modules_babel_runtime_helpers_esm_toConsumableArray__WEBPACK_IMPORTED_MODULE_2__["default"])(child);

实则是webpack忽略了异常,而vite编译工具更严格,出了问题直接就不让执行了。
8 el-dialog弹框的兼容性问题。
element-ui种el-dialog采用的是visible属性的方式
1
但是在element-plus这种方式是不行的,应该是框架在双向绑定和单向属性做了区分,应调整为:model-value
另外v-el-drag-dialog不是element的指令,没必要,去掉。
1
10 指令中vue.use is not a function问题
即使在开发环境下面vue2的指令写法,也不会出错。但是部署在生产环境,却不能这么干,必须将指令调整为vue3能够理解的。

1

const clickOutside = {
    bind(el, binding, vnode) {
        function documentHandler(e) {
            // 这里判断点击的元素是否是本身,是本身,则返回
            if (el.contains(e.target)) {
            return false;
            }

            // 判断指令中是否绑定了函数
            if ( binding.expression) {
            // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
            binding.value(e);
            }
        }
        // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
        el.__vueClickOutside__ = documentHandler;
        document.addEventListener('click', documentHandler);
    },
    update() {},
    unbind(el, binding) { // 解除事件监听
        document.removeEventListener('click', el.__vueClickOutside__);
        delete el.__vueClickOutside__;
    }
}


export default clickOutside

11 template的使用
在 Vue.js 中, 标签并不是一个“虚拟”标签,而是一个特殊的标签,它允许你组织代码结构,但它本身不会在最终的渲染输出中呈现。 标签经常用于包裹多个元素,或者与条件渲染(如 v-if、v-else-if、v-else)、列表渲染(v-for)以及插槽(slot)等特性一起使用
左侧el-col布局,在element-ui中可以的,但是element-plus中是不行的,因此可以采用<template>代替,不会产生多余的dom节点
1
12 v-show同时显示出来的问题

<el-table-column prop="operateDate" label="日期" min-width="150">
                <template #header>
                    <p class="headerSlot"><i>日期</i></p>
                </template>
                <template #default="scope">
                  <span v-show="!scope.row.isEditCell" class="editRow">{{scope.row.operateDate+'111'}}</span>
                  {{scope.row.isEditCell}}
                    <!-- @keyup.enter="" -->
                  <el-date-picker
                    v-show="scope.row.isEditCell"
                    v-model="scope.row.operateDate"
                    @change="changeRowDate(scope.row)"
                    type="date"
                    value-format="YYYY-MM-DD"
                    placeholder="选择日期111"
                    class="editRow"
                    :clearable="false"
                    @blur="cellBlur(scope.row,scope.$index)" @focus="cellFocus(scope.row)"
                     :ref="'operateDate'+scope.row.id"
                    :picker-options="pickerOptions">
                </el-date-picker>
                </template>
              </el-table-column>

调试发现scope.row.isEditCell明明是false,应该只显示span,为什么日期也显示出来了呢?
1
v-show不起作用很大一部分是因为该标签设置了display属性样式如display: flex,该样式的优先级高于v-show的display:none/display:block,导致v-show不起作用。
按照这篇文章给的思路,调试
1
新的element-plus默认均是flex布局。
1
解决办法是使用v-if

<el-table-column prop="operateDate" label="日期" min-width="150">
                <template #header>
                    <p class="headerSlot"><i>日期</i></p>
                </template>
                <template #default="scope">
                  <span v-if="!scope.row.isEditCell" class="editRow">{{scope.row.operateDate}}</span>
                    <!-- @keyup.enter="" -->
                  <el-date-picker
                    v-else
                    v-model="scope.row.operateDate"
                    @change="changeRowDate(scope.row)"
                    type="date"
                    value-format="YYYY-MM-DD"
                    placeholder="选择日期111"
                    class="editRow"
                    :clearable="false"
                    @blur="cellBlur(scope.row,scope.$index)" @focus="cellFocus(scope.row)"
                     :ref="'operateDate'+scope.row.id"
                    :picker-options="pickerOptions">
                </el-date-picker>
                </template>
              </el-table-column>

经过5篇博客,整个Vue2升级到vue3完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warrah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值