目錄
資料不會回應,可能是用法有問題
data# 中定義好" >1. 將原本要新增的屬性提前在data# 中定義好
userInfo" >2. 直接替換掉userInfo
Vue.set" >#3. 使用Vue.set
$forceUpdate" >4. 使用$forceUpdate
針對數組的特定方式
filter更简单" >文本格式化,filter更简单
filter 简化逻辑" >使用filter 简化逻辑
filter" >注册全局filter
开发了插件库,来安装一下
Vue.use的用法" >了解Vue.use的用法
element-ui的安装逻辑" >模拟element-ui的安装逻辑
插件的应用场景
提高Vue渲染性能,了解一下Object.freeze
结语
首頁 web前端 Vue.js 分享Vue專案中會用到的一些實戰技巧點

分享Vue專案中會用到的一些實戰技巧點

Sep 28, 2020 pm 06:00 PM
vue

分享Vue專案中會用到的一些實戰技巧點

在開發Vue的過程中,我們常常會遇到一些這樣或那樣的問題,然後要卡好半天,等問題解決了才發現原來一些細節知識點還是沒有掌握好。今天小編整理了幾個在專案中會用到的一些實戰技巧點,希望可以幫助到正在努力賺錢的你。江湖規矩,先讚後看,豔遇不斷。

資料不會回應,可能是用法有問題

前幾天有朋友給我發了一段程式碼,然後說Vuebug,他明明寫的沒問題,為啥資料就不回應呢,一定是Vuebug?我覺得他比尤雨溪要牛逼,高攀不起,就沒理他了。但確實有時候我們在開發時候會遇到資料不回應的狀況,那該怎麼辦呢?例如下面這段程式碼:

<template>
  <div>
    <div>
      <span>用户名: {{ userInfo.name }}</span>
      <span>用户性别: {{ userInfo.sex }}</span>
      <span v-if="userInfo.officialAccount">
        公众号: {{ userInfo.officialAccount }}
      </span>
    </div>
    <button @click="handleAddOfficialAccount">添加公众号</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      userInfo: {
        name: &#39;子君&#39;,
        sex: &#39;男&#39;
      }
    }
  },
  methods: {
    // 在这里添加用户的公众号
    handleAddOfficialAccount() {
      this.userInfo.officialAccount = &#39;前端有的玩&#39;
    }
  }
}
</script>
登入後複製

在上面的程式碼中,我們希望為使用者資訊裡面加上公眾號屬性,但是透過this.userInfo.officialAccount = '前端有的玩'添加之後,並沒有生效,這是為什麼呢?

這是因為在Vue內部,資料回應是透過使用Object.definePrototype監聽物件的每一個鍵的getter,setter方法來實現的,但透過這個方法只能監聽到已有屬性,新增的屬性是無法監聽到的,但我就是想監聽,小編你說咋辦吧。以下小編提供了四種方式,如果有更多方式,歡迎下方留言區告訴我。

1. 將原本要新增的屬性提前在data# 中定義好

例如上面的公眾號,我可以提前在userInfo裡面定義好,這樣就不是新增屬性了,就像下面這樣

data() {
    return {
      userInfo: {
        name: &#39;子君&#39;,
        sex: &#39;男&#39;,
        // 我先提前定义好
        officialAccount: &#39;&#39;
      }
    }
  }
登入後複製

2. 直接替換掉userInfo

雖然無法為userInfo裡面新增新的屬性,但是因為userInfo已經定義好了,所以我直接修改userInfo的值不就可以了麼,所以也可以像下面這樣寫

this.userInfo = {
  // 将原来的userInfo 通过扩展运算法复制到新的对象里面
  ...this.userInfo,
  // 添加新属性
  officialAccount: &#39;前端有的玩&#39;
}
登入後複製

#3. 使用Vue.set

其實上面兩種方法都有點取巧的嫌疑,其實對於新增屬性,Vue官方專門提供了一個新的方法Vue.set用來解決新增屬性無法觸發數據響應。

Vue.set 方法定義

/**
* target 要修改的对象
* prpertyName 要添加的属性名称
* value 要添加的属性值
*/
Vue.set( target, propertyName, value )
登入後複製

#上面的程式碼使用Vue.set可以修改為

import Vue from &#39;vue&#39;

// 在这里添加用户的公众号
handleAddOfficialAccount() {
  Vue.set(this.userInfo,&#39;officialAccount&#39;, &#39;前端有的玩&#39;)
}
登入後複製

但是每次要用到set方法的時候,還要把Vue引入進來,好麻煩,所以為了簡便起見, Vue又將set方法掛載到了Vue的原型鏈上了,即Vue.prototype.$set = Vue.set,所以在Vue元件內部可以直接用this.$set取代Vue.set

this.$set(this.userInfo,&#39;officialAccount&#39;, &#39;前端有的玩&#39;)
登入後複製

小編發現有許多同學不知道什麼時候應該用Vue.set,其實只有當你要賦值的屬性還沒定義的時候需要使用Vue,set,其他時候一般不會需要使用。

4. 使用$forceUpdate

#我覺得$forceUpdate的存在,讓許多前端開發者不會再去注意資料雙向綁定的原理,因為不論什麼時候,反正我修改了data之後,呼叫一下$forceUpdate就會讓Vue元件重新渲染,bug是不會存在的。但是實際上這個方法並不建議使用,因為它會造成許多不必要的效能消耗。

針對數組的特定方式

其實不只是對象,數組也存在資料修改之後不回應的情況,例如下面這段程式碼

<template>
  <div>
    <ul>
      <li v-for="item in list" :key="item">
        {{ item }}
      </li>
    </ul>
    <button @click="handleChangeName">修改名称</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      list: [&#39;张三&#39;, &#39;李四&#39;]
    }
  },
  methods: {
    // 修改用户名称
    handleChangeName() {
      this.list[0] = &#39;王五&#39;
    }
  }
}
</script>
登入後複製

上面的程式碼希望將張三的名字修改為王五,實際上這個修改並不能生效,這是因為Vue不能偵測到以下變動的陣列:

  • # #當你利用索引直接設定一個項目時,例如: this.list[index] = newValue

  • 修改陣列的length#屬性,例如: this.list.length = 0

所以在上例中通过this.list[0] = '王五' 是无法触发数据响应的,那应该怎么办呢?像上面提到的Vue.set$forceUpdate都可以解决这个问题,比如Vue.set可以这样写

Vue.set(this.list,0,&#39;王五&#39;)
登入後複製

除了那些方法之外,Vue还针对数组提供了变异方法

在操作数组的时候,我们一般会用到数据提供的许多方法,比如push,pop,splice等等,在Vue中调用数组上面提供的这些方法修改数组的值是可以触发数据响应的,比如上面的代码改为以下代码即可触发数据响应

this.list.splice(0,1,&#39;王五&#39;)
登入後複製

实际上,如果Vue仅仅依赖gettersetter,是无法做到在数组调用push,pop等方法时候触发数据响应的,因此Vue实际上是通过劫持这些方法,对这些方法进行包装变异来实现的。

Vue对数组的以下方法进行的包装变异:

  • push
  • pop
  • shift
  • unshift
  • splice
  • sort
  • reverse

所以在操作数组的时候,调用上面这些方法是可以保证数据可以正常响应,下面是Vue源码中包装数组方法的代码:

var original = arrayProto[method];
  def(arrayMethods, method, function mutator () {
    // 将 arguments 转换为数组
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
    var result = original.apply(this, args);
    // 这儿的用法同dependArray(value),就是为了取得dep
    var ob = this.__ob__;
    var inserted;
    switch (method) {
      case &#39;push&#39;:
      case &#39;unshift&#39;:
        inserted = args;
        break
      case &#39;splice&#39;:
        inserted = args.slice(2);
        break
    }
    // 如果有新的数据插入,则插入的数据也要进行一个响应式
    if (inserted) { ob.observeArray(inserted); }
   // 通知依赖进行更新
    ob.dep.notify();
    return result
  });
登入後複製

文本格式化,filter更简单

使用filter 简化逻辑

我想把时间戳显示成yyyy-MM-DD HH:mm:ss的格式怎么办?是需要在代码中先将日期格式化之后,再渲染到模板吗?就像下面这样

<template>
  <div>
    {{ dateStr }}
    <ul>
      <li v-for="(item, index) in getList" :key="index">
        {{ item.date }}
      </li>
    </ul>
  </div>
</template>
<script>
import { format } from &#39;@/utils/date&#39;
export default {
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  },
  computed: {
    dateStr() {
      return format(this.date, &#39;yyyy-MM-DD HH:mm:ss&#39;)
    },
    getList() {
      return this.list.map(item => {
        return {
          ...item,
          date: format(item.date, &#39;yyyy-MM-DD HH:mm:ss&#39;)
        }
      })
    }
  }
}
</script>
登入後複製

像上面的写法,针对每一个日期字段都需要调用format,然后通过计算属性进行转换?这时候可以考虑使用Vue提供的filter去简化

<template>
  <div>
    <!--使用过滤器-->
    {{ dateStr | formatDate }}
    <ul>
      <li v-for="(item, index) in list" :key="index">
        <!--在v-for中使用过滤器-->
        {{ item.date | formatDate }}
      </li>
    </ul>
  </div>
</template>
<script>
import { format } from &#39;@/utils/date&#39;
export default {
  filters: {
    formatDate(value) {
      return format(value, &#39;yyyy-MM-DD HH:mm:ss&#39;)
    }
  },
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  }
}
</script>
登入後複製

通过上面的修改是不是就简单多了

注册全局filter

有些过滤器使用的很频繁,比如上面提到的日期过滤器,在很多地方都要使用,这时候如果在每一个要用到的组件里面都去定义一遍,就显得有些多余了,这时候就可以考虑Vue.filter注册全局过滤器

对于全局过滤器,一般建议在项目里面添加filters目录,然后在filters目录里面添加

// filters\index.js

import Vue from &#39;vue&#39;
import { format } from &#39;@/utils/date&#39;

Vue.filter(&#39;formatDate&#39;, value => {
  return format(value, &#39;yyyy-MM-DD HH:mm:ss&#39;)
})
登入後複製

然后将filters里面的文件引入到main.js里面,这时候就可以在组件里面直接用了,比如将前面的代码可以修改为

<template>
  <div>
    <!--使用过滤器-->
    {{ dateStr | formatDate }}
    <ul>
      <li v-for="(item, index) in list" :key="index">
        <!--在v-for中使用过滤器-->
        {{ item.date | formatDate }}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  }
}
</script>
登入後複製

是不是更简单了

开发了插件库,来安装一下

在使用一些UI框架的时候,经常需要使用Vue.use来安装, 比如使用element-ui时候,经常会这样写:

import Vue from &#39;vue&#39;;
import ElementUI from &#39;element-ui&#39;;
import &#39;element-ui/lib/theme-chalk/index.css&#39;;
Vue.use(ElementUI,{size: &#39;small&#39;});
登入後複製

使用了Vue.use之后,element-ui就可以直接在组件里面使用了,好神奇哦(呸,娘炮)。接下来我们实现一个简化版的element来看如何去安装。

了解Vue.use的用法

Vue.use是一个全局的方法,它需要在你调用 new Vue() 启动应用之前完成,Vue.use的参数如下

/**
* plugin: 要安装的插件 如 ElementUI
* options: 插件的配置信息 如 {size: &#39;small&#39;}
*/
Vue.use(plugin, options)
登入後複製

模拟element-ui的安装逻辑

想一下,使用Vue.use(ElementUI,{size: 'small'}) 之后我们可以用到哪些element-ui提供的东西

// 这个是一个按钮组件
import Button from &#39;@/components/button&#39;

// loading 指令
import loadingDirective from &#39;@/components/loading/directive&#39;

// loading 方法
import loadingMethod from &#39;@/components/loading&#39;

export default {
  /**
   * Vue.use 需要插件提供一个install方法
   * @param {*} Vue Vue
   * @param {*} options 插件配置信息
   */
  install(Vue, options) {
    console.log(options)
    // 将组件通过Vue.components 进行注册
    Vue.components(Button.name, Button)

    // 注册全局指令
    Vue.directive(&#39;loading&#39;, loadingDirective)

    // 将loadingMethod 挂载到 Vue原型链上面,方便调用
    Vue.prototype.$loading = loadingMethod
  }
}
登入後複製

通过上面的代码,已经实现了一个丐版的element-ui插件,这时候就可以在main.js里面通过Vue.use进行插件安装了。大家可能会有疑问,为什么我要用这种写法,不用这种写法我照样可以实现功能啊。小编认为这种写法有两个优势

  • 标准化,通过提供一种统一的开发模式,无论对插件开发者还是使用者来说,都有一个规范去遵循。

  • 插件缓存,Vue.use 在安装插件的时候,会对插件进行缓存,即一个插件如果安装多次,实际上只会在第一次安装时生效。

插件的应用场景

  • 添加全局方法或者 property。

  • 添加全局资源:指令/过滤器/过渡等。

  • 通过全局混入来添加一些组件选项。

  • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

  • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如element-ui

提高Vue渲染性能,了解一下Object.freeze

当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。但是这个过程实际上是比较消耗性能的,所以对于一些有大量数据但只是展示的界面来说,并不需要将property加入到响应式系统中,这样可以提高渲染性能,怎么做呢,你需要了解一下Object.freeze

Vue官网中,有这样一段话:这里唯一的例外是使用 Object.freeze(),这会阻止修改现有的 property,也意味着响应系统无法再_追踪_变化。这段话的意思是,如果我们的数据使用了Object.freeze,就可以让数据脱离响应式系统,那么该如何做呢?

比如下面这个表格,因为只是渲染数据,这时候我们就可以通过Object.freeze来优化性能

<template>
  <el-table :data="tableData" >
    <el-table-column prop="date" label="日期" width="180" />
    <el-table-column prop="name" label="姓名" width="180" />
    <el-table-column prop="address" label="地址" />
  </el-table>
</template>
<script>
export default {
  data() {
    const data = Array(1000)
      .fill(1)
      .map((item, index) => {
        return {
          date: &#39;2020-07-11&#39;,
          name: `子君${index}`,
          address: &#39;大西安&#39;
        }
      })
    return {
      // 在这里我们用了Object.freeze
      tableData: Object.freeze(data)
    }
  }
}
</script>
登入後複製

有的同学可能会有疑问,如果我这个表格的数据是滚动加载的,你这样写我不就没法再给tableData添加数据了吗?是,确实没办法去添加数据了,但还是有办法解决的,比如像下面这样

export default {
  data() {
    return {
      tableData: []
    }
  },
  created() {
    setInterval(() => {
      const data = Array(1000)
        .fill(1)
        .map((item, index) => {
          // 虽然不能冻结整个数组,但是可以冻结每一项数据
          return Object.freeze({
            date: &#39;2020-07-11&#39;,
            name: `子君${index}`,
            address: &#39;大西安&#39;
          })
        })
      this.tableData = this.tableData.concat(data)
    }, 2000)
  }
}
登入後複製

合理的使用Object.freeze,是可以节省不少渲染性能,特别对于IE浏览器,效果还是很明显的,赶快去试试吧。

最后如果你现在需要开发移动端项目,可以了解一下小编整理的一个开箱即用框架 vue-vant-base,也许可以帮到你哦

结语

不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特?梵高

相关推荐:

2020年前端vue面试题大汇总(附答案)

vue教程推荐:2020最新的5个vue.js视频教程精选

更多编程相关知识,请访问:编程入门!!

以上是分享Vue專案中會用到的一些實戰技巧點的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

vue怎麼給按鈕添加函數 vue怎麼給按鈕添加函數 Apr 08, 2025 am 08:51 AM

可以通過以下步驟為 Vue 按鈕添加函數:將 HTML 模板中的按鈕綁定到一個方法。在 Vue 實例中定義該方法並編寫函數邏輯。

vue中的watch怎麼用 vue中的watch怎麼用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 選項允許開發者監聽特定數據的變化。當數據發生變化時,watch 會觸發一個回調函數,用於執行更新視圖或其他任務。其配置選項包括 immediate,用於指定是否立即執行回調,以及 deep,用於指定是否遞歸監聽對像或數組的更改。

vue多頁面開發是啥意思 vue多頁面開發是啥意思 Apr 07, 2025 pm 11:57 PM

Vue 多頁面開發是一種使用 Vue.js 框架構建應用程序的方法,其中應用程序被劃分為獨立的頁面:代碼維護性:將應用程序拆分為多個頁面可以使代碼更易於管理和維護。模塊化:每個頁面都可以作為獨立的模塊,便於重用和替換。路由簡單:頁面之間的導航可以通過簡單的路由配置來管理。 SEO 優化:每個頁面都有自己的 URL,這有助於搜索引擎優化。

vue返回上一頁的方法 vue返回上一頁的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一頁有四種方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 組件window.history.back(),方法選擇取決於場景。

vue.js怎麼引用js文件 vue.js怎麼引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三種:直接使用 &lt;script&gt; 標籤指定路徑;利用 mounted() 生命週期鉤子動態導入;通過 Vuex 狀態管理庫進行導入。

vue遍歷怎麼用 vue遍歷怎麼用 Apr 07, 2025 pm 11:48 PM

Vue.js 遍歷數組和對像有三種常見方法:v-for 指令用於遍歷每個元素並渲染模板;v-bind 指令可與 v-for 一起使用,為每個元素動態設置屬性值;.map 方法可將數組元素轉換為新數組。

vue的div怎麼跳轉 vue的div怎麼跳轉 Apr 08, 2025 am 09:18 AM

Vue 中 div 元素跳轉的方法有兩種:使用 Vue Router,添加 router-link 組件。添加 @click 事件監聽器,調用 this.$router.push() 方法跳轉。

See all articles