vue 实践技巧合集

本文不涉及罕见API使用方法等,大部分内容都是基于对vue的一些实践而已。由于涉嫌投机取巧,可能会带来一些不符合规范的副作用,请根据项目要求酌情使用。

1. 多个页面都使用的到的方法,放在vue.prototype上会很方便

刚接触 vue 的时候做过一件傻事,因为封装了一个异步请求接口post,放在 post.js 文件里面,然后在每个需要使用异步请求的页面引入

import port from './xxxx/xxxx/post'

如果只是这样,还没什么,我们可以写好一个页面以后再复制,可以保证每个页面都有上面的语句。但是如果每个文件所在的目录层级不一样呢?

// 假设正常是这样
import port from '../xxxx/xxxx/post'
// 目录加深一级,就变成这样
import port from '../../xxxx/xxxx/post'
// 再加深一级的样子
import port from '../../../xxxx/xxxx/post'

当然,这个时候,我们可以用 别名 @/xxxx/post,但是还是少不了要每个页面引用。 那我们来看看,用vue.prototype 有多方便? 首先,你得在 vue 的入口文件( vue-cli 生成的项目的话,默认是 /src/main.js)里面做如下设置

 import port from './xxxx/xxxx/post'

 vue.prototype.$post = post 

这样,我们就可以在所有的 vue 组件(页面)里面使用 this.post() 方法了,就像 vue 的亲儿子一样

把方法挂在到 prototype 上的时候,最好加一个 $ 前缀,避免跟其他变量冲突

不要挂载太多方法到 prototype 上,只挂载一些使用频率非常高的

2. 需要响应的数据,在获取到接口数据的时候,先设置

大家有没有很经常碰到这样都一种情况,在循环列表的时候,我们需要给列表项一个控制显示的属性,如 是否可删除,是否已选中等等,而后端接口一般不会返回这种字段,因为这属于纯前端展示的,跟后端没啥关系,比如后端给的数据如下

[
  {name: 'abc', age: 18},
  {name: 'def', age: 20},
  {name: 'ghi', age: 22},
]

我们不妨假设以上数据为学生列表

然后我们需要渲染这个列表,在每一项后面显示一个勾选按钮,如果用户打勾,则这个按钮是绿色,默认这个按钮是灰色,这个时候,上表是没有满足这个渲染条件的数据,而如果我们在用户打勾的时候,再去添加这个数据的话,正常的做法是无法及时响应的。

如果我们在获取到数据的时候,先给数组的每一项都加一个是否打勾的标志,就可以解决这个问题了,我们假设我们获取到的数据是 res.list

res.list.map(item => { 
  item.isTicked = false
})

这么做的原理是vue无法对不存在的属性做响应,所以我们在获取到数据的时候,先把需要的属性加上去,然后在赋值给data,这样data接收到数据的时候,已经存在这个属性了,所以会响应。当然还有其他方法可以实现。

3. 封装全局基于promise的异步请求方法

看过很多项目的源码,发现大部分的异步请求都是直接使用 axios 之类的方法,如下

axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
})
 .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

如果有跨域,或者需要设置 http 头等,还需要加入更多的配置,而这些配置,对于同一个项目来说,基本都是一样的,不一样的只有 url 跟参数,既然这样,那我吗为什么不把它封装成一个方法呢?

function post (url,param) {
    return axios({
      method: 'post',
      url: url,
      data: param
      ... axios 的其他配置
    })
}

再结合第一点,我们就可以再任意 vue 实例中这样使用

let param = {
  firstName: 'Fred',
  lastName: 'Flintstone'
}
this.post('/user/12345',param)
.then(...)
.catch(...)

有没有比原始的简单很多呢?如果你的项目支持 async await,还可以这样用

let param = {
  firstName: 'Fred',
  lastName: 'Flintstone'
}
let res  = await this.post('/user/12345',param)
console.log(res) // res 就是异步返回的数据

tip: await 关键字必须在 被 async 修饰的函数里面使用

4. 如果你觉得有时候,你真的需要父子组件共享一个值,不如试试穿个引用类型过去

vue 的父子组件传值,有好多种方法,这里就不一一列举了,但是今天我们要了解的,是利用 javascript 的引用类型特性,还达到另一种传值的目的

假设有这么一个需求,父组件需要传 3 个值到子组件,然后再子组件里面改动后,需要立马再父组件上作出响应,我们通常的做法上改完以后,通过 this.$emit 发射事件,然后再父组件监听对应的事件,然而这么做应对一两个数据还好,如果传的数据多了,会累死人。 我们不妨把这些要传递的数据,包再一个对象/数组 里面,然后在传给子组件

<subComponent :subData="subData"></subComponent>
data () {
  return {
    subData: {
      filed1: 'field1',
      filed2: 'field2',
      filed3: 'field3',
      filed4: 'field4',
      filed5: 'field5',
    }
  }
}

这样,我们在子组件里面改动 subData 的内容,父组件上就能直接作出响应,无需 this.$emit 或 vuex 而且如果有其他兄弟组件的话,只要兄弟组件也有绑定这个 subData ,那么兄弟组件里面的 subData 也能及时响应

tip: 首先,这么做我个人上感觉有点不符合规范的,如果没有特别多的数据,还是乖乖用 this.$emit 吧,其次,这个数据需要有特定的条件才能构造的出来,并不是所有情况都适用。

5. 异步请求的参数在data里面构造好,用一个对象包起来,会方便很多

有做过类似 ERP 类型的系统的同学,一定碰到过这样的一个场景,一个列表,有 N 个过滤条件,这个时候通常我们这么绑定

 <input type="text" v-model="field1">
 <input type="text" v-model="field2">
 <input type="text" v-model="field3">
 ....
 <input type="text" v-model="fieldn">
data () {
 return {
   field1: 'value1',
   field2: 'value2',
   field3: 'value3',
   ...
   fieldn:'valuen'
 }
}

然后提交数据的时候这样:

 var param = {
   backend_field1: this.field1,
   backend_field2: this.field2,
   backend_field3: this.field3,
   ...
   backend_fieldn: this.fieldn
 }
 this.post(url,param)

如你看到的,每次提交接口,都要去构造参数,还很容易遗漏,我们不妨这样:先去接口文档里面看一下后端需要的字段名称,然后

<input type="text" v-model="queryParam.backend_field1">
    <input type="text" v-model="queryParam.backend_field2">
    <input type="text" v-model="queryParam.backend_field3">
    ....
    <input type="text" v-model="queryParam.backend_fieldn">
   ```
  
   ```javascript
   data () {
    return {
      queryParam:{
        backend_field1: 'value1'
        backend_field2: 'value2'
        backend_field3: 'value3'
        ...
        backend_fieldn: 'valuen'
      }
    }
   }
   ```
   然后提交数据的时候这样:
   ```javascript
    this.post(url,this.queryParam)
   ```

是的,这样做也是有局限性的,比如你一个数据在 2 个地方共用,比如前端组件绑定的是一个数组,你需要提交给后端的是 2 个字符串(例:`element ui` 的时间控件),不过部分特殊问题稍微处理一下,也比重新构建一个参数简单不是吗?

6. 如果你只在子组件里面改变父组件的一个值,不妨试试$emit('input'),会直接改变v-model

我们正常的父子组件通信是 父组件通过 props 传给子组件,子组件通过 this.$emit('eventName',value) 通知父组件绑定在 @eventName 上的方法来做相应的处理。 但是这边有个特例,vue 默认会监听组件的 input 事件,而且会把子组件里面传出来的值,赋给当前绑定到 v-model 上的值

正常用法 - 父组件

<template>
  <subComponent :data="param" @dataChange="dataChangeHandler"></subComponent>
</template>

<script >
  export default {
    data () {
      return {
        param:'xxxxxx'
      }
    },
    methods:{
      dataChangeHandler (newParam) {
        this.param = newParam
      }
    }
  }
</script>

正常用法 - 子组件

<script >
  export default {
    methods:{
      updateData (newParam) {
        this.$emit('dataChange',newParam)
      }
    }
  }
</script>

利用默认 input 事件 - 父组件

<template>
  <subComponent  v-model="param"></subComponent>
</template>

利用默认 input 事件 - 子组件

<script >
  export default {
    methods:{
      updateData (newParam) {
        this.$emit('input',newParam)
      }
    }
  }
</script>

这样,我们就能省掉父组件上的一列席处理代码,vue 会自动帮你处理好

tip: 这种方法只适用于改变单个值的情况,且子组件对父组件只需简单的传值,不需要其他附加操作(如更新列表)的情况。

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值