填坑之路:Vue中那些容易被忽略的

記錄一些在使用Vue開發(fā)中常見的坑婴氮。

聲明本人菜鳥一只竿裂,一些描述可能會(huì)有偏頗纵苛,大佬輕錘剿涮,歡迎拍磚。

小葵花課堂開課啦攻人!

插槽相關(guān):slotslot-scope

單個(gè)插槽 | 匿名插槽

以上兩種叫法也就說明了它的含義:

  • 一個(gè)組件中只能有一個(gè)該類插槽
  • 該類插槽不設(shè)置name屬性
<!-- 父組件 -->
<template>
  <div class="father">
    <h3>父組件</h3>
    <child>
      <div class="tmpl">
        <span>test1</span>
        <span>test2</span>
        <span>test3</span>
      </div>
    </child>
  </div>
</template>

<!-- 子組件 -->
<template>
  <div class="child">
    <h3>子組件</h3>
    <slot></slot>
  </div>
</template>

子組件中定義的slot將被父組件中child內(nèi)包裹的html模板所替代取试,即渲染后成:

<div class="father">
  <h3>父組件</h3>
  <div class="child">
    <h3>子組件</h3>
    <div class="tmpl">
      <span>test1</span>
      <span>test2</span>
      <span>test3</span>
    </div>
  </div>
</div>
具名插槽

該插槽name屬性不為空,且可以在一個(gè)組件中出現(xiàn)多次怀吻。

<!-- 父組件 -->
<template>
  <div class="father">
    <h3>父組件</h3>
    <child>
      <div class="tmpl" slot="first">
        <span>test1</span>
        <span>test2</span>
        <span>test3</span>
      </div>
      <div class="tmpl" slot="second">
        <span>test4</span>
        <span>test5</span>
        <span>test6</span>
      </div>
      <div class="tmpl">
        <span>test7</span>
        <span>test8</span>
        <span>test9</span>
      </div>
    </child>
  </div>
</template>

<!-- 子組件 -->
<template>
  <div class="child">
    <h3>子組件</h3>
     <!-- 具名插槽 -->
    <slot name="first"></slot>
     <!-- 具名插槽 -->
    <slot name="second"></slot>
     <!-- 匿名插槽 -->
    <slot></slot>
  </div>
</template>

組件中匿名插槽可與具名插槽同時(shí)使用瞬浓,并且:

  • 聲明了name的具名插槽將在父組件中找到與其對(duì)應(yīng)名稱的slot屬性,并將html模版替換到其中
  • 未聲明name的將找到對(duì)應(yīng)的未聲明slot屬性的html模版做替換。
作用域插槽

觀察可以發(fā)現(xiàn)烙博,以上兩種插槽的html模版的內(nèi)容都是由父組件指定的瑟蜈,那如果我想展示來自子組件的內(nèi)容該怎么辦呢?

所以就有了第三種插槽渣窜,我們稱之為作用域插槽铺根,坊間也叫攜帶數(shù)據(jù)的插槽,顧名思義乔宿,這種插槽可以攜帶數(shù)據(jù)給到父組件中的html模板位迂。

<!-- 父組件 -->
<template>
  <div class="father">
    <h3>父組件</h3>
    <child>
      <template slot-scope='scope'>
        <div class="tmpl">
          <span v-for='u in scope.data'>test1</span>
        </div>
      </template>
    </child>
  </div>
</template>

<!-- 子組件 -->
<template>
  <div class="child">
    <h3>子組件</h3>
     <!-- 作用域插槽 -->
    <slot :data="arr"></slot>
  </div>
</template>
<script>
export default {
  data () {
    return {
      arr: ['test1','test2','test3']
    }
  }
}
</script>

子組件中定義了一個(gè)數(shù)組data傳給父組件展示,父組件以${slotScopeName}.data的格式去接收這個(gè)來自子組件的數(shù)組加以展示详瑞。

想給第三方UI庫Event加自定義參數(shù)時(shí)

<el-date-picker v-model="editForm[item.name]" 
    placeholder="選擇日期"
    :editable="false" style="width:100%"
    @change="(value) => changeHandler(value, item.name)">
</el-date-picker>

如上掂林,使用箭頭函數(shù),return一個(gè)新的自定義函數(shù)坝橡,在自定義函數(shù)changeHandler中加入你想要的參數(shù)泻帮。

同路由不同參數(shù)時(shí)

如果由 app/12345 跳轉(zhuǎn)到 app/23456,兩個(gè)路由可能都是app/:id计寇,用的同一個(gè)組件锣杂,所以vue并不會(huì)重新走一遍生命周期,導(dǎo)致一些可能的數(shù)據(jù)沒更新的bug番宁。

所以元莫,一個(gè)比較好的解決方案是監(jiān)控路由的變化來刷新一個(gè)必要的參數(shù)。

watch: {
    '$route.params': function (newValue) {
      this.init()
    }
}

watch

如上是我們常用的 watch蝶押,但可能你不知道watch 還有兩個(gè)比較實(shí)用的配置:deepimmediate踱蠢。

deep

deep,默認(rèn)值是 false棋电。顧名思義即表示深入觀察茎截,watch會(huì)將obj一層層往下遍歷,給對(duì)象的所有屬性都添加了監(jiān)聽离陶〖诨ⅲ可想而知,這一做法的性能耗費(fèi)比較大招刨。

watch: {
    obj: {
        handler (newVal, oldVal) {
            console.log('obj的屬性變化了')
        },
        deep: true
    },
    
}
// 建議使用
watch: {
    'obj.key': {
        handler (newVal, oldVal) {
            console.log('obj的屬性key變化了')
        }
    },
    
}
immediate

immediate霎俩,默認(rèn)值為 false。顧名思義即表示立即監(jiān)聽沉眶,在定義了 handler 方法后將立即執(zhí)行一次打却。

watch: {
 firstName: {
  handler (newval, oldVal) {
   this.fullName = `${newval} ${this.lastName}`
  },
  immediate: true
 }
}

定時(shí)器

很多時(shí)候我們可能會(huì)有寫定時(shí)器的需求(比如有個(gè)輪詢?nèi)蝿?wù)),當(dāng)我們離開這個(gè)頁面時(shí)谎倔,你會(huì)發(fā)現(xiàn)定時(shí)任務(wù)還在跑柳击,性能炸了。

于是我們可以這么干:

data() {
    return {
        timer: null
    }
}
methods: {
    timing() {
        this.timer = setInterval(() => {
            // dosomething
        }, 100)
    }
}
beforeDestroy() {
    clearInterval(this.timer) // 在組件即將銷毀時(shí)清掉定時(shí)任務(wù)
    this.timer = null // 變量釋放
}

關(guān)鍵就在當(dāng)我們離開這個(gè)頁面(組件銷毀前)時(shí)清掉定時(shí)任務(wù)片习。

路由懶加載

Vue的首屏渲染慢飽受詬病捌肴。

究其原因蹬叭,在于webpack打出來的包太大,導(dǎo)致在進(jìn)入首頁的時(shí)候需要加載的文件大且多状知。

那么我們就可以使用懶加載將頁面切分(vue-router支持webpack內(nèi)置的異步模塊加載系統(tǒng)秽五,使用較少的路由組件不再打包到bundles中,只在路由被訪問到時(shí)按需加載)饥悴,隨用隨載坦喘,減少首頁加載的負(fù)擔(dān)。

常規(guī)非懶加載路由配置
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Home from '@/components/Home'
import Profile from '@/components/Profile'

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/login',
        name: 'Login',
        compontent: Login
    }, {
        path: '/home',
        name: 'Home',
        compontent: Home
    }, {
        path: '/profile',
        name: 'Profile',
        compontent: Profile
    }]
})

懶加載路由配置

以下列了常用的三種寫法西设,webpack都支持瓣铣。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/login',
        name: 'Login',
        compontent: resolve => require(['@/component/Login'], resolve)
    }, {
        path: '/home',
        name: 'Home',
        compontent: () => import(/* webpackChunkName: "home" */  '@/component/Home')
    }, {
        path: '/profile',
        name: 'Profile',
        compontent: r => require.ensure([], () => r(require('@/component/Profile')), 'profile')
    }]
})

Computed

先來看一段代碼:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <title>Computed</title>

    </head>

    <body>
        <div id="app">
            <label for="">FirstName:<input v-model="firstName"/></label><br>
            <label for="">LastName:<input v-model="lastName"/></label><br>
            <label for="">NickName<input v-model="nickName"/></label><br>
            <p>名稱:{{name}}</p>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script>
            new Vue({
                el: '#app',
                data: function() {
                    return {
                        firstName: '',
                        lastName: '',
                        nickName: ''
                    }
                },
                computed: {
                    name: function() {
                        console.log('觸發(fā)computed了')
                        if (this.nickName) {
                            return this.nickName
                        } else {
                            return this.firstName + '.' + this.lastName
                        }
                    }
                }
            })
        </script>
    </body>
</html>

天真時(shí)候的我們可能會(huì)以為每當(dāng)nickNamefirstNamelastName三者任一變化都將重新觸發(fā)name的變更贷揽。

其實(shí)不然棠笑,當(dāng)nickName有值(不為空)后,重新觸發(fā)依賴收集禽绪,此后將移除對(duì)firstNamelastName的依賴腐晾;而當(dāng)nickName再次為空值時(shí),又將會(huì)收集到對(duì)firstNamelastName等的依賴丐一。

也就是說藻糖,依賴收集是動(dòng)態(tài)的。

re-render相關(guān)

還是看一段代碼:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <title>Re-render</title>

    </head>

    <body>
        <div id="app">
            <div v-for="(item, index) in items" :key="index">
                <div v-if="index === 0">
                    <input v-model="formData[item.key]">
                </div>
                <div v-else>{{item.key}}:{{Date.now()}}</div>
            </div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script>
            new Vue({
                el: '#app',
                data: function() {
                    return {
                        items: [{
                            key: 'input'
                        }, {
                            key: 'Re-render'
                        }],
                        formData: {
                            input: ''
                        }
                    }
                }
            })
        </script>
    </body>
</html>

以上可能是一種常見的場(chǎng)景库车。我們會(huì)驚奇的發(fā)現(xiàn)巨柒,當(dāng)input框中值發(fā)生變化,頁面re-render了一個(gè)新的時(shí)間戳柠衍。不難看出問題出在Date.now()洋满,這是一個(gè)方法(雖然沒定義在實(shí)例的methods中),故而每當(dāng)template重新渲染時(shí)會(huì)再次觸發(fā)一次method珍坊,進(jìn)而引發(fā)意料之外的事故牺勾。

<div id="app">
    <div>
        <label>input:<input v-model="model"/></label>
    </div>
    <div>
        <child :items="makeItems()"></child>
    </div>
</div>

以上可能更能說明問題,一些場(chǎng)景下我們可能沒深考慮或下意識(shí)地直接使用一個(gè)method做一些props傳給子組件阵漏。那么當(dāng)輸入值model變化時(shí)觸發(fā)父組件模板重新渲染驻民,childitems是從method來的所以會(huì)被重新做一遍,產(chǎn)生不必要的麻煩履怯。

所以回还,一些場(chǎng)景下為了避免這種不必要的麻煩,還是推薦使用computed叹洲,因?yàn)?strong>計(jì)算屬性是基于它們的依賴進(jìn)行緩存的柠硕,而method在觸發(fā)重新渲染時(shí)總會(huì)再次執(zhí)行函數(shù),不做緩存运提。

...

未完待續(xù)蝗柔。闻葵。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末癣丧,一起剝皮案震驚了整個(gè)濱河市笙隙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坎缭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件签钩,死亡現(xiàn)場(chǎng)離奇詭異掏呼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)铅檩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門憎夷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昧旨,你說我怎么就攤上這事拾给。” “怎么了兔沃?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵蒋得,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我乒疏,道長(zhǎng)额衙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任怕吴,我火速辦了婚禮窍侧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘转绷。我一直安慰自己伟件,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布议经。 她就那樣靜靜地躺著斧账,像睡著了一般。 火紅的嫁衣襯著肌膚如雪煞肾。 梳的紋絲不亂的頭發(fā)上其骄,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音扯旷,去河邊找鬼拯爽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钧忽,可吹牛的內(nèi)容都是我干的毯炮。 我是一名探鬼主播逼肯,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼桃煎!你這毒婦竟也來了篮幢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤为迈,失蹤者是張志新(化名)和其女友劉穎三椿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葫辐,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搜锰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耿战。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛋叼。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖剂陡,靈堂內(nèi)的尸體忽然破棺而出狈涮,到底是詐尸還是另有隱情,我是刑警寧澤鸭栖,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布歌馍,位于F島的核電站,受9級(jí)特大地震影響晕鹊,放射性物質(zhì)發(fā)生泄漏骆姐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一捏题、第九天 我趴在偏房一處隱蔽的房頂上張望玻褪。 院中可真熱鬧,春花似錦公荧、人聲如沸带射。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窟社。三九已至,卻和暖如春绪钥,著一層夾襖步出監(jiān)牢的瞬間灿里,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工程腹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匣吊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像色鸳,于是被迫代替她去往敵國(guó)和親社痛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容命雀,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容蒜哀。關(guān)于...
    云之外閱讀 5,052評(píng)論 0 29
  • vue概述 在官方文檔中,有一句話對(duì)Vue的定位說的很明確:Vue.js 的核心是一個(gè)允許采用簡(jiǎn)潔的模板語法來聲明...
    li4065閱讀 7,233評(píng)論 0 25
  • 一:什么是閉包吏砂?閉包的用處撵儿? (1)閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。在本質(zhì)上狐血,閉包就 是將函數(shù)內(nèi)部和函數(shù)外...
    xuguibin閱讀 9,636評(píng)論 1 52
  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,221評(píng)論 0 6
  • 夏至日痕長(zhǎng)淀歇, 趨車赴定場(chǎng)。 揮桿綠茵處氛雪, 入洞喜群芳。 杯舉翠微潤(rùn)耸成, 暢懷花徑旁报亩。 生辰許心愿, 山水共情長(zhǎng)井氢。
    飛雪姐姐閱讀 133評(píng)論 0 2