Home >Web Front-end >JS Tutorial >Comprehensive summary: Summary of solving problems encountered during the use of vue (must read)

Comprehensive summary: Summary of solving problems encountered during the use of vue (must read)

不言
不言Original
2018-08-17 14:29:245083browse

This article brings you a comprehensive summary: a summary of the solutions to problems encountered during the use of vue (must read). The article introduces the understanding of this in js. It has certain reference value and is necessary. Friends can refer to it, I hope it will be helpful to you.

This article is purely a summary of some personal experience in daily practice. It is a little trick, not a brilliant technology. If it helps you, I would be honored.

This article does not involve rare API usage methods, etc. Most of the content is based on some practices of vue. Due to suspicion of opportunism, it may bring some non-standard side effects, please use it as appropriate according to the project requirements.

  1. This method is used on multiple pages. It will be very convenient to put it on vue.prototype

    New to this vue I did a stupid thing, because I encapsulated an asynchronous request interface post, put it in the post.js file, and then in each need Page introduction using asynchronous requests

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

    If it’s just like this, it’s nothing. We can write a page and copy it later to ensure that each page has the above statement. But what if the directory level of each file is different?

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

    Of course, at this time, we can use the alias @/xxxx/post, but it is still necessary to quote each page.
    Let’s see how convenient it is to use vue.prototype?
    First, you have to do it in the entry file of vue (for projects generated by vue-cli, the default is /src/main.js) Set

     import port from './xxxx/xxxx/post'
    
     vue.prototype.$post = post

    as follows, so that we can use the this.post() method in all vue components (pages), just like vue 's own son

    tip: When hanging the method on prototype, it is best to add a $ prefix to avoid conflict with other variables

    til again: Don’t mount too many methods to prototype, only mount some very frequently used

  2. that require response data, when getting the interface data, first set

    Have you ever encountered a situation like this very often? When looping the list, we need to give the list item a control display Properties, such as whether it can be deleted, whether it has been selected, etc., and the back-end interface generally does not return this kind of field, because it is purely front-end display and has nothing to do with the back-end. For example, the data given by the back-end is as follows

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

    We might as well assume that the above data is a student list

    Then we need to render this list and display a check button behind each item. If the user checks, the button will be green. By default, this button is Gray, at this time, the above table does not have data that meets this rendering condition. If we add this data when the user ticks, the normal approach will not be able to respond in time.

    If we first add a check mark to each item in the array when we get the data, we can solve this problem. We assume that the data we get is res. list

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

    The principle of doing this is that vue cannot respond to non-existent attributes, so when we get the data, we first add the required attributes, and then When assigning a value to data, when data receives the data, this attribute already exists, so it will respond. There are of course other ways to do it. But for someone with obsessive-compulsive disorder, I still prefer this approach

  3. Encapsulate the global asynchronous request method based on promise

    I have read the source code of many projects and found that most asynchronous requests directly use methods such as axios, as follows

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

    If there is cross-domain, or need to be sethttp First class, more configurations need to be added, and these configurations are basically the same for the same project. The only differences are url and parameters. In this case, Then why don't I encapsulate it into a method?

    function post (url,param) {
        return axios({
          method: 'post',
          url: url,
          data: param
          ... axios 的其他配置
        })
    }
    tip: It turns out that I used an extra layer of promise to wrap it up, which is too much for simple needs. I feel that Nuggets users @ The sun and the moon are easy. Point out that

    combined with the first point, we can use it in any vue example

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

    Is it much simpler than the original one? If your project supports async await, you can also use

    let param = {
      firstName: 'Fred',
      lastName: 'Flintstone'
    }
    let res  = await this.post('/user/12345',param)
    console.log(res) // res 就是异步返回的数据
    tip like this: await keyword must be modified by async in Use
  4. in the function. If you feel that sometimes, you really need the parent and child components to share a value, why not try passing a reference type over there# There are many ways to pass values ​​between parent and child components of

    ##vue, so I won’t list them all here. But what we want to know today is to use the reference type of javascript feature, and also achieves another purpose of passing value

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

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

    这样,我们在子组件里面改动 subData 的内容,父组件上就能直接作出响应,无需 this.$emitvuex 而且如果有其他兄弟组件的话,只要兄弟组件也有绑定这个 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. data 里面的数据多的时候,给每个数据加一个备注,会让你后期往回看的时候很清晰

    续上一点,data 里面有很多数据的时候,可能你写的时候是挺清晰的,毕竟都是你自己写的东西,可是过了十天半个月,或者别人看你的代码,相信我,不管是你自己,还是别人,都是一头雾水(记忆力超出常人的除外),所以我们不妨给每个数据后面加一个备注

    data () {
     return {
       field1: 'value1',  // 控制xxx显示
       field2: 'value2',  // 页面加载状态
       field3: [],        // 用户列表
       ...
       fieldn: 'valuen'   // XXXXXXXX
     }
    }
  7. 逻辑复杂的内容,尽量拆成组件

    假设我们有一个这样的场景:

    <p>
       <p>姓名:{{user1.name}}</p>
       <p>性别:{{user1.sex}}</p>
       <p>年龄:{{user1.age}}</p>
       ...此处省略999个字段...
       <p>他隔壁邻居的阿姨家小狗的名字:{{user1.petName}}</p>
    </p>
    <-- 当然,显示中我们不会傻到不用 v-for,我们假设这种情况无法用v-for -->
    <p>
        <p>姓名:{{user2.name}}</p>
        <p>性别:{{user2.sex}}</p>
        <p>年龄:{{user2.age}}</p>
        ...此处省略999个字段...
        <p>他隔壁邻居的阿姨家小狗的名字:{{user2.petName}}</p>
    </p>

    这种情况,我们不妨把[用户]的代码,提取到一个组件里面:
     假设如下代码,在 comUserInfo.vue

    <template>
     <p>
       <p>姓名:{{user.name}}</p>
       <p>性别:{{user.sex}}</p>
       <p>年龄:{{user.age}}</p>
       ...此处省略999个字段...
       <p>他隔壁邻居的阿姨家小狗的名字:{{user.petName}}</p>
     </p>
    </template>
    
    <script >
    export  default {
     props:{
       user:{
         type:Object,
         default: () => {}
       }
     }
    }
    </script>

    然后原来的页面可以改成这样(省略掉导入和注册组件,假设注册的名字是 comUserInfo ):

    <comUserInfo :user="user1"/>
    <comUserInfo :user="user2"/>

    这样是不是清晰很多?不用看注释,都能猜的出来,这是2个用户信息模块, 这样做,还有一个好处就是出现错误的时候,你可以更容易的定位到错误的位置。

  8. 如果你只在子组件里面改变父组件的一个值,不妨试试 $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: 这种方法只适用于改变单个值的情况,且子组件对父组件只需简单的传值,不需要其他附加操作(如更新列表)的情况。

    补充一个 this.$emit('update:fidldName',value) 方法 (感谢掘金用户 @日月为易。 指出)
     具体用法如下:

    父组件

        <subComponent field1.sync="param1" field2.sync="param2"></subComponent>

    子组件

    <script >
      export default {
        methods:{
          updateData1 (newValue) {
            this.$emit('update:field1',newValue)
          },
          updateData2 (newValue) {
            this.$emit('update:field2',newValue)
          }
        }
      }
    </script>

    该方法,个人认为比较适用于 要更新的数据不能绑定在 v-model 的情况下,或者要双向通信的数据大于 1 个(1个也可以用,但我个人更推荐 input 的方式, 看个人喜好吧),但又不会很多的情况下.

  9. conponents放在 Vue options 的最上面

    不知道大家有没有这样的经历: 导入组件,然后在也页面中使用,好的,报错了,为啥?忘记注册组件了,为什么会经常忘记注册组件呢?因为正常的一个 vue 实例的结构大概是这样的:

    import xxx form 'xxx/xxx'
    export default {
      name: 'component-name',
      data () {
        return {
          // ...根据业务逻辑的复杂程度,这里省略若干行
        }
      },
      computed: {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      created () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      mounted () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
      methods () {
        // ...根据业务逻辑的复杂程度,这里省略若干行
      },
    }

    我不知道大家正常是把 components 属性放在哪个位置,反正我之前是放在最底下,结果就是导致经常犯上述错误。

    后面我把 components 调到第一个去了

    import xxx form 'xxx/xxx'
    export default {
      components: {
        xxx
      },
      // 省略其他代码
    }

    从此以后,妈妈再也不用担心我忘记注册组件了,导入和注册都在同一个位置,想忘记都难。

  10. 大部分情况下,生命周期里面,不要有太多行代码,可以封装成方法,再调用

    看过很多代码,包括我自己之前的,在生命周期里面洋洋洒洒的写了一两百行的代码,如:把页面加载的时候,该做的事,全部写在 created 里面,导致整个代码难以阅读,完全不知道你在页面加载的时候,做了些什么,
     这个时候,我们不妨把那些逻辑封装成方法,然后在生命周期里面直接调用:

    created () {
      // 获取用户信息
      this.getUserInfo()
      // 获取系统信息
      this.getSystemInfo()
      // 获取配置
      this.getConfigInfo()
    },
    methods:{
      // 获取用户信息
      getUserInfo () {...},
      // 获取系统信息
      getSystemInfo () {...},
      // 获取配置
      getConfigInfo () {...},
    }

    这样是不是一眼就能看的出,你在页面加载的时候做了些什么?

    tip: 这个应该算是一个约定俗成的规范吧,只是觉得看的比较多这样写的,加上我自己初学的时候,也这么做了,所以写出来,希望新入坑的同学能避免这个问题
  11. 少用 watch,如果你觉得你好多地方都需要用到 watch,那十有八九是你对 vueAPI 还不够了解

    vue 本身就是一个数据驱动的框架,数据的变动,能实时反馈到视图上去,如果你想要根据数据来控制试图,正常情况一下配合 computed 服用就能解决大部分问题了,而视图上的变动,我们一般可以通过监听 input change 等事件,达到实时监听的目的,
     所以很少有需求使用到 watch 的时候,至少我最近到的十来个项目里面,是没有用过 watch 当然,并不是说 watch 是肯定没用处, vue 提供这个api,肯定是有他的道理,也有部分需求是真的需要用到的,只是我觉得应该很少用到才对,如果你觉得到处都得用到的话,
     那么我觉得 十有八九你应该多去熟悉一下 computedvue 的其他 api

相关推荐:

Vue登录注册的实现方法(代码解析)

ES6中全新的数字方法总结(必看)

The above is the detailed content of Comprehensive summary: Summary of solving problems encountered during the use of vue (must read). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn