新聞中心
[[376218]]

前言
Vue 3.x 的Pre-Alpha 版本。后面應(yīng)該還會有 Alpha、Beta 等版本,預(yù)計至少要等到 2020 年第一季度才有可能發(fā)布 3.0 正式版;
所以應(yīng)該趁還沒出來加緊打好 Vue2.x 的基礎(chǔ);
Vue基本用法很容易上手,但是有很多優(yōu)化的寫法你就不一定知道了,本文從列舉了 36 個 vue 開發(fā)技巧;
后續(xù) Vue 3.x 出來后持續(xù)更新.
1.require.context()
1.場景:如頁面需要導(dǎo)入多個組件,原始寫法:
- import titleCom from '@/components/home/titleCom'
- import bannerCom from '@/components/home/bannerCom'
- import cellCom from '@/components/home/cellCom'
- components:{titleCom,bannerCom,cellCom}
2.這樣就寫了大量重復(fù)的代碼,利用 require.context 可以寫成
- const path = require('path')
- const files = require.context('@/components/home', false, /\.vue$/)
- const modules = {}
- files.keys().forEach(key => {
- const name = path.basename(key, '.vue')
- modules[name] = files(key).default || files(key)
- })
- components:modules
這樣不管頁面引入多少組件,都可以使用這個方法
3.API 方法
- 實際上是 webpack 的方法,vue 工程一般基于 webpack,所以可以使用
- require.context(directory,useSubdirectories,regExp)
- 接收三個參數(shù):
- directory:說明需要檢索的目錄
- useSubdirectories:是否檢索子目錄
- regExp: 匹配文件的正則表達(dá)式,一般是文件名
2.watch
2.1 常用用法
1.場景:表格初始進來需要調(diào)查詢接口 getList(),然后input 改變會重新查詢
- created(){
- this.getList()
- },
- watch: {
- inpVal(){
- this.getList()
- }
- }
2.2 立即執(zhí)行
2.可以直接利用 watch 的immediate和handler屬性簡寫
- watch: {
- inpVal:{
- handler: 'getList',
- immediate: true
- }
- }
2.3 深度監(jiān)聽
3.watch 的 deep 屬性,深度監(jiān)聽,也就是監(jiān)聽復(fù)雜數(shù)據(jù)類型
- watch:{
- inpValObj:{
- handler(newVal,oldVal){
- console.log(newVal)
- console.log(oldVal)
- },
- deep:true
- }
- }
此時發(fā)現(xiàn)oldVal和 newVal 值一樣;
因為它們索引同一個對象/數(shù)組,Vue 不會保留修改之前值的副本;
所以深度監(jiān)聽雖然可以監(jiān)聽到對象的變化,但是無法監(jiān)聽到具體對象里面那個屬性的變化
3. 14種組件通訊
3.1 props
這個應(yīng)該非常屬性,就是父傳子的屬性;
props 值可以是一個數(shù)組或?qū)ο?
- // 數(shù)組:不建議使用
- props:[]
- // 對象
- props:{
- inpVal:{
- type:Number, //傳入值限定類型
- // type 值可為String,Number,Boolean,Array,Object,Date,Function,Symbol
- // type 還可以是一個自定義的構(gòu)造函數(shù),并且通過 instanceof 來進行檢查確認(rèn)
- required: true, //是否必傳
- default:200, //默認(rèn)值,對象或數(shù)組默認(rèn)值必須從一個工廠函數(shù)獲取如 default:()=>[]
- validator:(value) {
- // 這個值必須匹配下列字符串中的一個
- return ['success', 'warning', 'danger'].indexOf(value) !== -1
- }
- }
- }
3.2 $emit
這個也應(yīng)該非常常見,觸發(fā)子組件觸發(fā)父組件給自己綁定的事件,其實就是子傳父的方法
- // 父組件
- // 子組件
- this.$emit('title',[{title:'這是title'}])
3.3 vuex
1.這個也是很常用的,vuex 是一個狀態(tài)管理器
2.是一個獨立的插件,適合數(shù)據(jù)共享多的項目里面,因為如果只是簡單的通訊,使用起來會比較重
3.API
- state:定義存貯數(shù)據(jù)的倉庫 ,可通過this.$store.state 或mapState訪問
- getter:獲取 store 值,可認(rèn)為是 store 的計算屬性,可通過this.$store.getter 或
- mapGetters訪問
- mutation:同步改變 store 值,為什么會設(shè)計成同步,因為mutation是直接改變 store 值,
- vue 對操作進行了記錄,如果是異步無法追蹤改變.可通過mapMutations調(diào)用
- action:異步調(diào)用函數(shù)執(zhí)行mutation,進而改變 store 值,可通過 this.$dispatch或mapActions
- 訪問
- modules:模塊,如果狀態(tài)過多,可以拆分成模塊,最后在入口通過...解構(gòu)引入
3.4 attrs和attrs和attrs和listeners
2.4.0 新增
這兩個是不常用屬性,但是高級用法很常見;
1.$attrs
場景:如果父傳子有很多值,那么在子組件需要定義多個 props
解決:$attrs獲取子傳父中未在 props 定義的值
- // 父組件
- // 子組件
- mounted() {
- console.log(this.$attrs) //{title: "這是標(biāo)題", width: "80", height: "80", imgUrl: "imgUrl"}
- },
相對應(yīng)的如果子組件定義了 props,打印的值就是剔除定義的屬性
- props: {
- width: {
- type: String,
- default: ''
- }
- },
- mounted() {
- console.log(this.$attrs) //{title: "這是標(biāo)題", height: "80", imgUrl: "imgUrl"}
- },
2.$listeners
場景:子組件需要調(diào)用父組件的方法
解決:父組件的方法可以通過 v-on="$listeners" 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時非常有用
- // 父組件
- // 子組件
- mounted() {
- console.log(this.$listeners) //即可拿到 change 事件
- }
如果是孫組件要訪問父組件的屬性和調(diào)用方法,直接一級一級傳下去就可以
3.inheritAttrs
- // 父組件
- // 子組件
- mounted() {
- console.log(this.$attrs) //{title: "這是標(biāo)題", width: "80", height: "80", imgUrl: "imgUrl"}
- },
- inheritAttrs默認(rèn)值為true,true的意思是將父組件中除了props外的屬性添加到子組件的根節(jié)點上(說明,即使設(shè)置為true,子組件仍然可以通過$attr獲取到props意外的屬性)
- 將inheritAttrs:false后,屬性就不會顯示在根節(jié)點上了
3.5 provide和inject
2.2.0 新增
描述:
provide 和 inject 主要為高階插件/組件庫提供用例。并不推薦直接用于應(yīng)用程序代碼中;
并且這對選項需要一起使用;
以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在起上下游關(guān)系成立的時間里始終生效。
- //父組件:
- provide: { //provide 是一個對象,提供一個屬性或方法
- foo: '這是 foo',
- fooMethod:()=>{
- console.log('父組件 fooMethod 被調(diào)用')
- }
- },
- // 子或者孫子組件
- inject: ['foo','fooMethod'], //數(shù)組或者對象,注入到子組件
- mounted() {
- this.fooMethod()
- console.log(this.foo)
- }
- //在父組件下面所有的子組件都可以利用inject
provide 和 inject 綁定并不是可響應(yīng)的。這是官方刻意為之的。
然而,如果你傳入了一個可監(jiān)聽的對象,那么其對象的屬性還是可響應(yīng)的,對象是因為是引用類型
- //父組件:
- provide: {
- foo: '這是 foo'
- },
- mounted(){
- this.foo='這是新的 foo'
- }
- // 子或者孫子組件
- inject: ['foo'],
- mounted() {
- console.log(this.foo) //子組件打印的還是'這是 foo'
- }
3.6 parent和parent和parent和children
$parent:父實例
$children:子實例
- //父組件
- mounted(){
- console.log(this.$children)
- //可以拿到 一級子組件的屬性和方法
- //所以就可以直接改變 data,或者調(diào)用 methods 方法
- }
- //子組件
- mounted(){
- console.log(this.$parent) //可以拿到 parent 的屬性和方法
- }
children和children和children和parent 并不保證順序,也不是響應(yīng)式的
只能拿到一級父組件和子組件
3.7 $refs
- // 父組件
- mounted(){
- console.log(this.$refs.home) //即可拿到子組件的實例,就可以直接操作 data 和 methods
- }
3.8 $root
- // 父組件
- mounted(){
- console.log(this.$root) //獲取根實例,最后所有組件都是掛載到根實例上
- console.log(this.$root.$children[0]) //獲取根實例的一級子組件
- console.log(this.$root.$children[0].$children[0]) //獲取根實例的二級子組件
- }
3.9 .sync
在 vue@1.x 的時候曾作為雙向綁定功能存在,即子組件可以修改父組件中的值;
在 vue@2.0 的由于違背單項數(shù)據(jù)流的設(shè)計被干掉了;
在 vue@2.3.0+ 以上版本又重新引入了這個 .sync 修飾符;
- // 父組件
- //編譯時會被擴展為
title = val"/> - // 子組件
- // 所以子組件可以通過$emit 觸發(fā) update 方法改變
- mounted(){
- this.$emit("update:title", '這是新的title')
- }
3.10 v-slot
2.6.0 新增
1.slot,slot-cope,scope 在 2.6.0 中都被廢棄,但未被移除
2.作用就是將父組件的 template 傳入子組件
3.插槽分類:
A.匿名插槽(也叫默認(rèn)插槽): 沒有命名,有且只有一個;
- // 父組件
- 任意內(nèi)容
我是匿名插槽
- // 子組件
我是默認(rèn)值 - //v-slot:default寫上感覺和具名寫法比較統(tǒng)一,容易理解,也可以不用寫
B.具名插槽: 相對匿名插槽組件slot標(biāo)簽帶name命名的;
- // 父組件
- 任意內(nèi)容
我是匿名插槽
- //子組件
我是默認(rèn)值
C.作用域插槽: 子組件內(nèi)數(shù)據(jù)可以被父頁面拿到(解決了數(shù)據(jù)只能從父頁面?zhèn)鬟f給子組件)
- // 父組件
- {{slotProps.user.firstName}}
- //slotProps 可以隨意命名
- //slotProps 接取的是子組件標(biāo)簽slot上屬性數(shù)據(jù)的集合所有v-bind:user="user"
- // 子組件
- {{ user.lastName }}
- data() {
- return {
- user:{
- lastName:"Zhang",
- firstName:"yue"
- },
- test:[1,2,3,4]
- }
- },
- // {{ user.lastName }}是默認(rèn)數(shù)據(jù) v-slot:todo 當(dāng)父頁面沒有(="slotProps")
3.11 EventBus
1.就是聲明一個全局Vue實例變量 EventBus , 把所有的通信數(shù)據(jù),事件監(jiān)聽都存儲到這個變量上;
2.類似于 Vuex。但這種方式只適用于極小的項目
3.原理就是利用on和on和on和emit 并實例化一個全局 vue 實現(xiàn)數(shù)據(jù)共享
- // 在 main.js
- Vue.prototype.$eventBus=new Vue()
- // 傳值組件
- this.$eventBus.$emit('eventTarget','這是eventTarget傳過來的值')
- // 接收組件
- this.$eventBus.$on("eventTarget",v=>{
- console.log('eventTarget',v);//這是eventTarget傳過來的值
- })
4.可以實現(xiàn)平級,嵌套組件傳值,但是對應(yīng)的事件名eventTarget必須是全局唯一的
3.12 broadcast和dispatch
vue 1.x 有這兩個方法,事件廣播和派發(fā),但是 vue 2.x 刪除了
下面是對兩個方法進行的封裝
- function broadcast(componentName, eventName, params) {
- this.$children.forEach(child => {
- var name = child.$options.componentName;
- if (name === componentName) {
- child.$emit.apply(child, [eventName].concat(params));
- } else {
- broadcast.apply(child, [componentName, eventName].concat(params));
- }
- });
- }
- export default {
- methods: {
- dispatch(componentName, eventName, params) {
- var parent = this.$parent;
- var name = parent.$options.componentName;
- while (parent && (!name || name !== componentName)) {
- parentparent = parent.$parent;
- if (parent) {
- name = parent.$options.componentName;
- }
- }
- if (parent) {
- parent.$emit.apply(parent, [eventName].concat(params));
- }
- },
- broadcast(componentName, eventName, params) {
- broadcast.call(this, componentName, eventName, params);
- }
- }
- }
3.13 路由傳參
1.方案一
- // 路由定義
- {
- path: '/describe/:id',
- name: 'Describe',
- component: Describe
- }
- // 頁面?zhèn)鲄?nbsp;
- this.$router.push({
- path: `/describe/${id}`,
- })
- // 頁面獲取
- this.$route.params.id
2.方案二
- // 路由定義
- {
- path: '/describe',
- name: 'Describe',
- omponent: Describe
- }
- // 頁面?zhèn)鲄?nbsp;
- this.$router.push({
- name: 'Describe',
- params: {
- id: id
- }
- })
- // 頁面獲取
- this.$route.params.id
3.方案三
- // 路由定義
- {
- path: '/describe',
- name: 'Describe',
- component: Describe
- }
- // 頁面?zhèn)鲄?nbsp;
- this.$router.push({
- path: '/describe',
- query: {
- id: id
- `}
- )
- // 頁面獲取
- this.$route.query.id
4.三種方案對比
方案二參數(shù)不會拼接在路由后面,頁面刷新參數(shù)會丟失
方案一和三參數(shù)拼接在后面,丑,而且暴露了信息
3.14 Vue.observable
2.6.0 新增
用法:讓一個對象可響應(yīng)。Vue 內(nèi)部會用它來處理 data 函數(shù)返回的對象;
- 返回的對象可以直接用于渲染函數(shù)和計算屬性內(nèi),并且會在發(fā)生改變時觸發(fā)相應(yīng)的更新;
- 也可以作為最小化的跨組件狀態(tài)存儲器,用于簡單的場景。
通訊原理實質(zhì)上是利用Vue.observable實現(xiàn)一個簡易的 vuex
- // 文件路徑 - /store/store.js
- import Vue from 'vue'
- export const store = Vue.observable({ count: 0 })
- export const mutations = {
- setCount (count) {
- store.count = count
- }
- }
- //使用
- {{count}}
4.render 函數(shù)
1.場景:有些代碼在 template 里面寫會重復(fù)很多,所以這個時候 render 函數(shù)就有作用啦
- // 根據(jù) props 生成標(biāo)簽
- // 初級
- // 優(yōu)化版,利用 render 函數(shù)減小了代碼重復(fù)率
Hello world!
2.render 和 template 的對比
前者適合復(fù)雜邏輯,后者適合邏輯簡單;
后者屬于聲明是渲染,前者屬于自定Render函數(shù);
前者的性能較高,后者性能較低。
5.異步組件
場景:項目過大就會導(dǎo)致加載緩慢,所以異步組件實現(xiàn)按需加載就是必須要做的事啦
1.異步注冊組件
3種方法
- // 工廠函數(shù)執(zhí)行 resolve 回調(diào)
- Vue.component('async-webpack-example', function (resolve) {
- // 這個特殊的 `require` 語法將會告訴 webpack
- // 自動將你的構(gòu)建代碼切割成多個包, 這些包
- // 會通過 Ajax 請求加載
- require(['./my-async-component'], resolve)
- })
- // 工廠函數(shù)返回 Promise
- Vue.component(
- 'async-webpack-example',
- // 這個 `import` 函數(shù)會返回一個 `Promise` 對象。
- () => import('./my-async-component')
- )
- // 工廠函數(shù)返回一個配置化組件對象
- const AsyncComponent = () => ({
- // 需要加載的組件 (應(yīng)該是一個 `Promise` 對象)
- component: import('./MyComponent.vue'),
- // 異步組件加載時使用的組件
- loading: LoadingComponent,
- // 加載失敗時使用的組件
- error: ErrorComponent,
- // 展示加載時組件的延時時間。默認(rèn)值是 200 (毫秒)
- delay: 200,
- // 如果提供了超時時間且組件加載也超時了,
- // 則使用加載失敗時使用的組件。默認(rèn)值是:`Infinity`
- timeout: 3000
- })
異步組件的渲染本質(zhì)上其實就是執(zhí)行2次或者2次以上的渲染, 先把當(dāng)前組件渲染為注釋節(jié)點, 當(dāng)組件加載成功后, 通過 forceRender 執(zhí)行重新渲染?;蛘呤卿秩緸樽⑨尮?jié)點, 然后再渲染為loading節(jié)點, 在渲染為請求完成的組件
2.路由的按需加載
- webpack< 2.4 時
- {
- path:'/',
- name:'home',
- components:resolve=>require(['@/components/home'],resolve)
- }
- webpack> 2.4 時
- {
- path:'/',
- name:'home',
- components:()=>import('@/components/home')
- }
- import()方法由es6提出,import()方法是動態(tài)加載,返回一個Promise對象,then方法的參數(shù)是加載到的模塊。類似于Node.js的require方法,主要import()方法是異步加載的。
6.動態(tài)組件
場景:做一個 tab 切換時就會涉及到組件動態(tài)加載
但是這樣每次組件都會重新加載,會消耗大量性能,所以
這樣切換效果沒有動畫效果,這個也不用著急,可以利用內(nèi)置的
7.遞歸組件
場景:如果開發(fā)一個 tree 組件,里面層級是根據(jù)后臺數(shù)據(jù)決定的,這個時候就需要用到動態(tài)組件
- // 遞歸組件: 組件在它的模板內(nèi)可以遞歸的調(diào)用自己,只要給組件設(shè)置name組件就可以了。
- // 設(shè)置那么House在組件模板內(nèi)就可以遞歸使用了,不過需要注意的是,
- // 必須給一個條件來限制數(shù)量,否則會拋出錯誤: max stack size exceeded
- // 組件遞歸用來開發(fā)一些具體有未知層級關(guān)系的獨立組件。比如:
- // 聯(lián)級選擇器和樹形控件
- 子組件,當(dāng)前層級值: {{index}}
遞歸組件必須設(shè)置name 和結(jié)束的閥值
8.函數(shù)式組件
定義:無狀態(tài),無法實例化,內(nèi)部沒有任何生命周期處理方法
規(guī)則:在 2.3.0 之前的版本中,如果一個函數(shù)式組件想要接收 prop,則 props 選項是必須的。
- 在 2.3.0 或以上的版本中,你可以省略 props 選項,所有組件上的特性都會被自動隱式解析為 prop
- 在 2.5.0 及以上版本中,如果你使用了單文件組件(就是普通的.vue 文件),可以直接在 template 上聲明functional
- 組件需要的一切都是通過 context 參數(shù)傳遞
context 屬性有:
1.props:提供所有 prop 的對象
2.children: VNode 子節(jié)點的數(shù)組
3.slots: 一個函數(shù),返回了包含所有插槽的對象
4.scopedSlots: (2.6.0+) 一個暴露傳入的作用域插槽的對象。也以函數(shù)形式暴露普通插槽。
5.data:傳遞給組件的整個數(shù)據(jù)對象,作為 createElement 的第二個參數(shù)傳入組件
6.parent:對父組件的引用
7.listeners: (2.3.0+) 一個包含了所有父組件為當(dāng)前組件注冊的事件監(jiān)聽器的對象。這是 data.on 的一個別名。
8.injections: (2.3.0+) 如果使用了 inject 選項,則該對象包含了應(yīng)當(dāng)被注入的屬性
{{item}}
9.components和 Vue.component
components:局部注冊組件
- export default{
- components:{home}
- }
Vue.component:全局注冊組件
- Vue.component('home',home)
10.Vue.extend
場景:vue 組件中有些需要將一些元素掛載到元素上,這個時候 extend 就起到作用了
是構(gòu)造一個組件的語法器
寫法:
- // 創(chuàng)建構(gòu)造器
- var Profile = Vue.extend({
- template: '
{{extendData}}實例傳入的數(shù)據(jù)為:{{propsExtend}}
',//template對應(yīng)的標(biāo)簽最外層必須只有一個標(biāo)簽- data: function () {
- return {
- extendData: '這是extend擴展的數(shù)據(jù)',
- }
- },
- props:['propsExtend']
- })
- // 創(chuàng)建的構(gòu)造器可以掛載到元素上,也可以通過 components 或 Vue.component()注冊使用
- // 掛載到一個元素上??梢酝ㄟ^propsData傳參.
- new Profile({propsData:{propsExtend:'我是實例傳入的數(shù)據(jù)'}}).$mount('#app-extend')
- // 通過 components 或 Vue.component()注冊
- Vue.component('Profile',Profile)
11.mixins
場景:有些組件有些重復(fù)的 js 邏輯,如校驗手機驗證碼,解析時間等,mixins 就可以實現(xiàn)這種混入
mixins 值是一個數(shù)組
- const mixin={
- created(){
- this.dealTime()
- },
- methods:{
- dealTime(){
- console.log('這是mixin的dealTime里面的方法');
- }
- }
- }
- export default{
- mixins:[mixin]
- }
12.extends
extends用法和mixins很相似,只不過接收的參數(shù)是簡單的選項對象或構(gòu)造函數(shù),所以extends只能單次擴展一個組件
- const extend={
- created(){
- this.dealTime()
- },
- methods:{
- dealTime(){
- console.log('這是mixin的dealTime里面的方法');
- }
- }
- }
- export defaul
當(dāng)前題目:Vue開發(fā)必須知道的36個技巧【近1W字】
標(biāo)題URL:http://m.jiaoqi3.com/article/coeiceg.html


咨詢
建站咨詢
