没有耕不完的地,只有填不完的坑

247 阅读5分钟

前段时间成功入了vue3的坑,相比已经用的比较熟练的vue2来说,3还是有很多未解之谜的,另外再加上ts这个神奇的语言,本来好好的代码,突然就喜庆的飘红了(啥时候基金也能这么红彤彤的就好了~)。俗话说得好,没有耕不完的地,只有填不完的坑,既然耕地不止,那填坑也得继续......

1、关于pinia单独引用

我们都知道轻巧实用的状态管理工具pinia可以很方便的集成到vue里,然后可以在vue组件内部直接使用。但是如果想要在单独的js文件中使用,直接通过store的方法,是获取不到的,会提示 getActivePinia was called with no active Pinia. Did you forget to install pinia? 类似的错误,所以如果需要在单独的js里使用pinia,还需要单独注册一下pinia。

// 新建一个 store.ts文件

import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;

// 在需要使用pinia的文件中引入
import pinia from '@/utils/store

然后就可以正常获取到相关的属性和方法了。

2、外部引入ts类型到defineProps报错

此处的使用场景如下

// type.ts
interface PropsType  {
}

// table.vue
import { PropsType } from './type'
const props = defineProps<PropsType>()

这时会报错 [@vue/compiler-sfc] type argument passed to defineProps() must be a literal type, or a reference to an interface or literal type.这个问题其实是vue本身的问题,接口或者对象可以使用引入类型,但是defineProps的泛型参数不能是一个导入的类型。所以此处可以直接在组件内部定义类型使用(暂时没想到合适的方法,有了解的大佬欢迎评论区留言指点)。

3、vue3使用keep-alive切换页面时报错

先贴出错误信息 parentComponent.ctx.deactivate is not a function,简化代码如下

<router-view v-slot="">
    <keep-alive>
        <Component :is="Component" v-if="" />
    <keep-alive>
    <component :is='Component' v-if="" />
</router-view>

此处,可以再路由里添加一个唯一的标识,如name,并在component上增加key值

<router-view v-slot="">
    <keep-alive>
        <Component :is="Component" :key="$route.name" v-if="" />
    <keep-alive>
    <component :is='Component' :key="$route.name" v-if="" />
</router-view>

4、引入sass样式无效

项目中引入sass样式,单独写到一个scss文件里,然后在style里引入即可。在页面中引入的时候,vscode也会提示一种语法@import url('')。如果这样引入,就会发现,样式根本不生效(具体原因咱也不知道,还是请教各位大佬留言指教~

此处的修改方法,只要把url去掉即可

<style lang='scss' scoped>
@import './style,scss'
</style>

5。vue中使用calc动态计算属性

大家都知道calc可以在样式中使用,来进行数值的计算。但是此处的场景是,calc内部的数值也是动态的,也就是都是些不确定的数值,此时就需要在行内进行样式的计算,直接上代码。

// 商品宽度计算
<div :style="goodItemStyle()"></div>

<script setup>
const goodItemStyle = () => {
  let itemColumnNum = goodTypeData.goodListColumnNumber  // 动态数值,初始化为5
  let itemRowNum = goodTypeData.goodListRowNumber    // 动态数值,初始化为4
  let itemRight = 10 * (Number(itemColumnNum) - 1) / itemColumnNum + 'px'
  let itemBot = 10 * (Number(itemRowNum) - 1) / itemRowNum
  let itemHeight = 200 / itemRowNum - itemBot + 'px'
  return `width: calc(100% / ${itemColumnNum} - ${itemRight}); height: ${itemHeight}; margin-right: ${itemRight}; margin-bottom: ${itemBot}px`
}
</script>

6、引入echart报错

依旧先抛出错误信息 Cannot read properties of undefined (reading ‘type‘)。这个错误的原因是因为定义的echart对象为响应式的,当渲染动态数据的时候,可能就会报错。

此时可以使用vue的markRaw,他可以标记一个对象使其不成为响应式。

import { ref, markRaw } from 'vue'

const orderMoneyRef = ref(null)

// 交易统计折线图
const drawOrderEchart = () => {
  orderMoney.value = echarts.getInstanceByDom(orderMoneyRef.value!)
  if (orderMoney.value == null) {
    orderMoney.value = markRaw(echarts.init(orderMoneyRef.value!));
  }
  ......
}

7、依旧是关于element-plus的问题

(1)日期选择器选择某段时间

这个没有什么问题,只是记录下相关方法

<el-radio-group class="time_radio_wrap" v-model="radioChange" @change="onRadioChange($event, searchFormRef)">
  <el-radio-button label='今日' />
  <el-radio-button label='昨日' />
  <el-radio-button label='近七日' />
  <el-radio-button label='本月' />
  <el-radio-button label='上月' />
</el-radio-group>

// 选择时间修改
const onRadioChange = (v: string, ref: FormInstance | undefined) => {
  let searchBegin: string | Moment = ""
  let searchEnd: string | Moment = ""
  if (v == "昨日") {
    let yes = moment(new Date()).subtract(1, 'days').format('YYYY-MM-DD');
    searchBegin = yes;
    searchEnd = yes;
  } else if (v == "近七日") {
    let sevenDay = moment(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000)).format("YYYY-MM-DD")
    searchBegin = sevenDay
    searchEnd = moment(new Date().getTime()).format("YYYY-MM-DD").valueOf()
  } else if (v == "上月") {
    searchBegin = moment().subtract(1, "months").startOf("months").format("YYYY-MM-DD").valueOf()
    searchEnd = moment().subtract(1, "months").endOf("months").format("YYYY-MM-DD").valueOf()
  } else if (v == "本月") {
    searchBegin = moment().subtract(0, "months").startOf("months").format("YYYY-MM-DD").valueOf()
    searchEnd = moment().subtract(0, "months").endOf("months").format("YYYY-MM-DD").valueOf()
  } else if (v == '今日') {
    let nowDay = moment(new Date()).format('YYYY-MM-DD')
    searchBegin = nowDay;
    searchEnd = nowDay;
  }
  dataForm.timeArr = [searchBegin, searchEnd]
}

(2)ts语法提示找不到名称“ElMessage”

前面的文章我们写了在vite配置中动态引入element-plus方法,所以在使用某些组件的时候就不需要单独引入了,但是在此处直接使用ElMessage时就会提示找不到相应名称。此时可以在tsconfig.jsoninclude引入 auto-imports.d.ts这个element-plus自动引入组件的ts文件,即可解决此报错。

// tsconfig.json

"include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "auto-imports.d.ts"
],
"exclude": [
    "node_modules"
]

8、vue pc端接入扫码枪

实际扫码枪的动作,就是模仿键盘的输入事件,可以通过window.document.obkeypress进行监听。

window.document.onkeypress = (e: any) => {
    console.log('code====>', e)
    if (window.event) {
      // IE
      scanData.scanNextCode = e.keyCode
    } else if (e.which) {
      scanData.scanNextCode = e.which
    }

    // 如果扫抢码是enter,则当次结束
    if (e.which === 13) {
      // 扫抢速度比手动输入快,因此手动输入时间不会让code长度大于2
      if (scanData.scanCode.length < 3) return;
      scanData.scanEnterCode = scanData.scanCode
      scanData.scanLastCode = ''
      scanData.scanLastTime = ''
      console.log('扫码完成===>', scanData.scanCode)
      return
    }

    scanData.scanNextTime = new Date().getTime()
    if (!scanData.scanLastCode && !scanData.scanLastTime) {
      scanData.scanCode = ''
      scanData.scanCode += e.key
      console.log('初次扫码===>', scanData.scanCode)
    }
    if (scanData.scanLastCode && scanData.scanLastTime && scanData.scanNextTime - scanData.scanLastTime > 500) {
      // 当扫码前又keypress事件时,防止首字符缺失
      scanData.scanCode = e.key
      console.log('缺失code===>', scanData.scanCode)
    } else if (scanData.scanLastCode && scanData.scanLastTime) {
      scanData.scanCode += e.key
      console.log('持续扫码===>', scanData.scanCode)
    }
    scanData.scanLastCode = scanData.scanNextCode  // 最终拿到扫码的值
    scanData.scanLastTime = scanData.scanNextTime
  }

上述方法是获取扫码结果的方法,但是如果存在一个input输入框,此时就需要在输入框获取焦点的时候去扫码,如果输入框失焦,很有可能扫码值获取不到了,此时可以增加方法。

<el-input ref="hideInputRef" @blur="againFocus" />

// 如果隐藏框失去焦点,自动获取焦点
const againFocus = () => {
  againTimeOut = setTimeout(() => {
    hideInputRef.value.focus()
  }, 20)
}

此方法就是隔段时间自动获取焦点,但是也有一个问题,就是页面中不能有其他的输入框,那样的话就没办法使用其他输入框的输入方法了。

好了,又一个阶段的坑填完了,除上述问题,在开发中还遇到了各种小问题,由于比较基础就不贴出来了,毕竟各位大佬都是资深专家,不会遇到那些基础小问题。