【vue记账】自制项目中碰到的一些问题以及思路总结

231 阅读5分钟

1、实现非移动端用户首次进入页面出现弹窗提示扫描二维码

实际功能碰到的不足:用户若执意使用pc端,则每次切换应用页面都会出现二维码弹窗提示,影响用户体验。

优化期待效果为 用户使用过程中取消一次即可不再重复提示,只需手动刷新页面可以再重新触发提示显示防止用户误触跳过。

项目结构描述: 在项目中使用了 插槽内容 ,所以这一部JS写在了使用插槽的组件当中。实现多页面具有共同效果。弹窗使用了ui库,组件内维护一个布尔值控制是否弹出。

思路: 使用vuex做状态管理,state中创建一个Boolean变量判断是否应该显示弹窗。默认为true(显示)。用户取消过一次后设置为false,后续依据此state变量进行控制。

在首次用户进来后判断客户端屏幕分辨率大小(500像素左右),若大于判定为非移动端,出现弹窗。在组件的created生命周期阶段触发函数showPopup()

created(){
          this.showPopup()
          //在此生命周期触发一次showPopup()
          },
methods: {
          showPopup() {
          //定义showPopup()
              if(this.$store.state.popup){
              //popup为state中的Boolean变量控制是否再次弹窗
                  if(document.documentElement.clientWidth>500){
                      this.show = true; //非移动端显示弹窗
                  }
                  this.$store.commit('changePopup')
                  //changePopup为store中mutation的函数,改变state的状态
              }
          },
      },

2、不同页面传递参数进行传值

记录一下使用的方法: this.$router.push

//$router : 是路由操作对象,只写对象

//$route : 路由信息对象,只读对象

query方式传参,假设当前为页面A 给路由为 /b 的页面B传递一个参数值。

//页面A
data() {
          return {
              item:{id:1}
              itemValue:'x'
          };
      },
methods:{
    onClick(item) {
      if(item.id===1){
        this.$router.push({
          path: '/b',
          query: {
            value: this.itemValue
          }
        })
      }
}

页面B接收参数,可以console.log在控制台看一下输出:

    this.getValue=this.$route.query.value

传参可以使用params和query两种方式。

(1)使用params传参只能用name来引入路由,因为params只能用name来引入路由,如果写成了path,接收参数页面会是undefined。

(2)使用query传参使用path来引入路由。

(3)params是路由的一部分,必须要在路由后面添加参数名。query是拼接在url后面的参数,没有也没关系。

(4)二者还有点区别,直白的来说query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示。

3、判定对象在值上是对等的问题

因为项目的单个数据是按对象的方式进行保存的,删除或者修改一个数据的时候需要找到localStorage里面的该数据就需要遍历存储里面的数据找出与判断选中的数据是否“相等”。但是因为是对象没法使用===的方式比较,一般的方法将对象转成字符串进行比较但是键值排序不一定相同也可能导致不相等。

思路: 可以使用一种方式将属性排序好转成字符串比较

function clone(data){
    return JSON.parse(JSON.stringify(data));
    //返回一个深拷贝的对象
  }
function isObjectChanged(source, comparison) {
        const sourceClone=clone(source)
        const comparisonClone=clone(comparison)
        //拿到拷贝后的对象对其进行操作
        const _source = JSON.stringify(sourceClone)
        const _comparison = JSON.stringify({...sourceClone,...comparisonClone})
        
        //展开运算符...会将comparisonClone与sourceClone同名键不同值进行覆盖掉,
        //所以实现键的排序一致,再转换成字符串进行比对酒可以了。类似Object.assign()
        return _source === _comparison
        
        //返回true代表相等
      }

若相等,接着就能对comparison这个对象数据进行操作了

4、渲染列表的时候key值的选择

key 的一个错误使用——使用 index 作为 key。

写 v-for 的时候,一般都是直接使用 index 作为它的 key 值,不得不说,有时候这不是一个好习惯。

如图,我在用transition-group给删除的数据做移除效果过渡动画的时候发现,删除一个li的数据所有的列表元素都会触发过渡动画,

image.png

按照官方的说法:key主要作用于Vue的virtual DOM算法,在diff new nodes list和old nodes list时,作为识别VNode的一个线索。

如果使用了key,Vue会根据keys的顺序记录element,曾经拥有了key的element如果不再出现的话,会被直接remove或者destoryed。

捕获bug产生的思考: 根据实际情况推断可能是key值的问题,因为结构不复杂思考一下原因,每次删除一个数据后,数组元素对应的的下标index就会-1发生改变,再次刷新数据后一样的元素内容但是key匹配index的值发生了变化与之前不一致了,前后key值发生变化所以vue没有重复利用相同类型元素减少渲染。导致之前的不是需要删除的元素也被remove从而触发离开的过渡动画。

需要额外权衡的内容: 对于v-for选择key值需要有唯一性。但删除元素index会发生改变,使用数据本身作为key标识又不具有唯一性。思来想去最好还是给数据添加一个属性,使得具备唯一性又不会被数据操作影响。时间戳或许是一个好的选择,在每次用户保存数据时额外添加一个属性,用new Date()生成的时间戳作为key

解决:data对象(用来保存数据的)增加一个createSybol属性,使用toISOString() 方法返回一个 ISO格式的字符串: YYYY-MM-DDTHH:mm:ss.sssZ。精确到毫秒,即使用户短时间内快速添加两个完全相同的记录也不会冲突。

const timer=new Date()
data.createTimeSybol=timer.toISOString()

补充: 有时候添加的属性是作为某些标识的,但是比较值对等的情况又不想比较这个标识的属性,那么就需要忽略掉属性使用delete,最好拷贝一下不要操作原数据,拿前面例子举例:

function clone(data){
    return JSON.parse(JSON.stringify(data));
    //返回一个深拷贝的对象
  }
function isObjectChanged(source, comparison) {
        const sourceClone=clone(source)
        const comparisonClone=clone(comparison)
        //拿到拷贝后的对象对其进行操作
        
        //——————————新增内容———————————
        delete sourceClone.createTimeSymbol
        delete comparisonClone.createTimeSymbol
        //————————————————————————————————
        
        const _source = JSON.stringify(sourceClone)
        const _comparison = JSON.stringify({...sourceClone,...comparisonClone})
        
        //展开运算符...会将comparisonClone与sourceClone同名键不同值进行覆盖掉,
        //所以实现键的排序一致,再转换成字符串进行比对酒可以了。类似Object.assign()
        return _source === _comparison
        
        //返回true代表相等
      }

5、webpack-dev-server 运行报错

Error: Cannot find module 'webpack-cli/bin/config-yargs'

webpack-cli与webpack-dev-server版本不一致导致的,webpack-cli降级到3

image.png

解决办法:

重新安装webpack-cli3版本 npm i webpack-cli@3 -D