记账项目中遇到的问题

198 阅读2分钟

0 Eslint报错的通用解决方式

  • 鸵鸟算法:在命令行和编译器中直接忽略
  • 按照提示修改代码
  • 根据报错信息修改配置文件,忽略一些特殊规则

1.导入文件夹的错误

报错信息:error: '__WebpackModuleApi' is not defined (no-undef)

解决方案 :在eslint的配置文件中添加以下这一句,全局可用

module.exports = { 
"globals":{ "__WebpackModuleApi":"writable" } 
}

2.Vue中的@

在Vue中@是src目录的别名

JS中的使用方法

import Tabs from '@/components/Tabs.vue';

CSS/SCSS的方法

@import "~@/assets/style/reset.scss";

3.Vue2中使用TS的基础模板

<template>
    <div>
    
    </div>
</template>

<script lang="ts">
import Vue from 'vue';
import {Component} from 'vue-property-decorator';

@Component
export default class Name extends Vue {
    XXX=YYY// 一般变量使用赋值写法
    zzz(){}// 函数直接写函数体即可
}
</script>

<style lang='scss' scoped>

</style>

注意TS不会对模板中的JS进行检查

4.固定位置的模块使用什么布局

在手机中fix定位会出现非常多的BUG,可以使用以下配合的flex布局

  1. 主体部分flex-grow:1,保证主体尽量占据剩余空间
  2. 超出页面长度时使用overflow:auto

5. Vue+TS中使用SVG

  1. shims-vue.d.ts中声明类型
declare module '*.svg' {
  const content: any
  export default content
}
  1. 配置

下载 svg-sprite-loader

然后在vue.config.js中添加

    chainWebpack: config => {
        const dir = path.resolve(__dirname, 'src/assets/icons')


        config.module
          .rule('svg-sprite')
          .test(/\.(svg)(\?.*)?$/)
          .include.add(dir).end()
          .use('svg-sprite-loader-mod').loader('svg-sprite-loader-mod').options({extract: false}).end()
          .use('svgo-loader').loader('svgo-loader')
          //.tap(options => ({...options, plugins: [{removeAttrs: {attrs: 'fill'}}]}))
          .end()
        config.plugin('svg-sprite').use(require('svg-sprite-loader-mod/plugin'), [{plainSprite: true}])
        config.module.rule('svg').exclude.add(dir)

    }

  1. 使用
  <svg class="icon" >
    <use :xlink:href="'#'+name"/>
  </svg>
  1. SVG自带颜色的问题
  • 进入SVG文件删除fill属性
  • 使用svgo-loader,但是最近的版本不太好用

6. 选中项

简而言之,根据情况变化出现或消失的内容尽量使用伪类实现,防止高度抖动

    &.selected::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 4px;
      background-color: #333;
    }

6. 父组件传递类

父组件

<div class="content" :class=" classPrefix &&`${classPrefix}-content`">

子组件

<template>
  <div class="layout-wrapper">
    <div class="content" :class=" classPrefix &&`${classPrefix}-content`">
      <slot></slot>
    </div>
    <Nav> </Nav>
  </div>
</template>

<script lang="ts">
export default {
  name: 'Layout',
  props:["classPrefix"]
};
</script>
<style lang='scss' scoped>
.layout-wrapper{
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.content{
  flex-grow: 1;
  overflow: auto;
}
</style>

7.类的绑定

一个Vue标签可以同时动态和静态绑定

<div class="content" :class=" classPrefix &&`${classPrefix}-content`">

有冒号的是动态绑定,动态和静态可以各有一个

8.Props装饰器的应用

子组件

@Prop(String) classPrefix?: string; //前一个类型是静态编译时检查的类型,后一个是动态运行时验证的类型

父组件

<XXX :classPrefix=YYY>

注意冒号,一定是动态绑定,否则会变成字符串

9.注意对象的引用,以及深克隆

数据收集完之后,想实现以下功能:每次按ok,将数据放到LocalStorage

在父组件Money.vueNumberPad新加了一个监听@submit="saveRecord"

<template>
  <layout class-prefix="layout">
    <NumberPad @update:value="onUpdateAmount" @submit="saveRecord"/>
    ...
    </layout>
</template>
<script lang="ts">
...
  export default class Money extends Vue{
    tags = ['餐饮','交通','购物','居家'];
    recordList: Record[] = [];
    record: Record = {tags: [], notes: '', type: '-', amount: 0};
    ...
    // 新增函数
    saveRecord(){
      this.recordList.push(this.record)
    }
    @Watch('recordList')
    onRecordListChange(){
      window.localStorage.setItem('recordList',JSON.stringify((this.recordList)))
    }
}
</script>

在子组件NumberPad.vue文件中的export default中的ok函数中添加代码

<script lang="ts">
...
export default class NumberPad extends Vue {
...
  ok(){
    this.$emit('update:value',this.output);
    this.$emit('submit',this.output); //新增
  }
}
</script>

这样用户每次点击ok,都会将数据上传至LocalStorae

但是这里出了一个错误,如下:

第一次输入1,点击ok,打印this.recordListamount是数字1,正确。

image.png

但第二次输入2,点击ok,再打印this.recordListamount得到两次结果都是2,出现bug。

image.png

Local Storage如下

image.png

原因是因为this.recordList.push(this.record)this.record只是引用,所以第一次ok和第二次ok,都只是引用了record的地址,结果是两个2。

修改代码,record2是一个深拷贝,相当于保存了this.record的副本这样就可以实现预想的功能了。

saveRecord(){
      const record2 = JSON.parse(JSON.stringify(this.record));
      this.recordList.push(record2)
      console.log(this.recordList);
    }

10. 子组件不能直接修改父组件属性

通过onValuechangedvalue进行变更,发送事件让父组件处理。

<template>
  <div>
    <label class="formItem">
      <span class="name">{{ this.fieldName }}</span>
      <input type="text"
             :value = "value"
             @input = "onValueChanged=($event.traget.value)"
      :placeholder="placeholder">
    </label>
  </div>
</template>

<script lang="ts">
...
export default class FormItem extends Vue{
  @Prop({default:''}) readonly value!:string;
...
  onValueChanged(value:string){
    this.$emit('update:value',value)
  }
}
</script>