首頁 > web前端 > js教程 > 主體

全面總結:vue使用過程中遇到的問題解決總結(必看)

不言
發布: 2018-08-17 14:29:24
原創
5054 人瀏覽過

這篇文章帶給大家的內容是關於全面總結:vue使用過程中遇到的問題解決總結(必看),文章介紹了對js中this的理解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

本文純屬個人平時實踐過程中的一些經驗總結,算是一點點小技巧吧,不是多麼高明的技術,如果對你有幫助,那麼不勝榮幸。

本文不涉及罕見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 的親兒子一樣

    tip: 把方法掛在到prototype 上的時候,最好加一個$ 前綴,避免跟其他變數衝突

    til again: 不要掛載太多方法到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 的其他配置
        })
    }
    登入後複製
    tip: 這裡原來我多用了一層promise包起來,對簡單的需求來說是太多餘了,感覺掘金用戶 @日月為易。 指出

    再結合第一點,我們就可以再任意 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.$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中全新的数字方法总结(必看)

以上是全面總結:vue使用過程中遇到的問題解決總結(必看)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!