Vue 基本使用知識點(diǎn)整理

Vue 基本使用

指令,插值

  • 插值馁龟,表達(dá)式
  • 指令崩侠,動態(tài)屬性
  • v-html:會有 XSS 風(fēng)險,會覆蓋子組件
<template>
    <div>
        <p>文本插值 {{message}}</p>
        <p>JS 表達(dá)式 {{ flag ? 'yes' : 'no' }} (只能是表達(dá)式坷檩,不能是 js 語句)</p>

        <p :id="dynamicId">動態(tài)屬性 id</p>

        <hr/>
        <p v-html="rawHtml">
            <span>有 xss 風(fēng)險</span>
            <span>【注意】使用 v-html 之后却音,將會覆蓋子元素</span>
        </p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            message: 'hello vue',
            flag: true,
            rawHtml: '指令 - 原始 html <b>加粗</b> <i>斜體</i>',
            dynamicId: `id-${Date.now()}`
        }
    }
}
</script>

computed 和 watch

  • computed 有緩存改抡,data 不變則不會重新計(jì)算
  • computed 可以設(shè)置 set 和 get 方法
  • watch 深度監(jiān)聽
    • watch 默認(rèn)不是深度監(jiān)聽
    • 啟動深度監(jiān)聽的話需要設(shè)置 deep 為 true
  • watch 監(jiān)聽引用類型,拿不到 old value

computed demo

<template>
    <div>
        <p>num {{num}}</p>
        <p>double1 {{double1}}</p>
        <input v-model="double2"/>
    </div>
</template>

<script>
export default {
    data() {
        return {
            num: 20
        }
    },
    computed: {
        double1() {
            return this.num * 2
        },
        double2: {
            get() {
                return this.num * 2
            },
            set(val) {
                this.num = val/2
            }
        }
    }
}
</script>

watch demo

<template>
    <div>
        <input v-model="name"/>
        <input v-model="info.city"/>
    </div>
</template>

<script>
export default {
    data() {
        return {
            name: '吉良吉影',
            info: {
                city: '上海'
            }
        }
    },
    watch: {
        name(oldVal, val) {
            console.log('watch name', oldVal, val) // 值類型系瓢,可正常拿到 oldVal 和 val
        },
        info: {
            handler(oldVal, val) {
                console.log('watch info', oldVal, val) // 引用類型阿纤,拿不到 oldVal 。因?yàn)橹羔樝嗤穆藭r已經(jīng)指向了新的 val
            },
            deep: true // 深度監(jiān)聽
        }
    }
}
</script>

class 和 style

注意事項(xiàng)

  • 使用動態(tài)屬性
  • 使用駝峰式寫法

代碼演示

<template>
    <div>
        <p :class="{ black: isBlack, yellow: isYellow }">使用 class</p>
        <p :class="[black, yellow]">使用 class (數(shù)組)</p>
        <p :style="styleData">使用 style</p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            isBlack: true,
            isYellow: true,

            black: 'black',
            yellow: 'yellow',

            styleData: {
                fontSize: '40px', // 轉(zhuǎn)換為駝峰式
                color: 'red',
                backgroundColor: '#ccc' // 轉(zhuǎn)換為駝峰式
            }
        }
    }
}
</script>

<style scoped>
    .black {
        background-color: #999;
    }
    .yellow {
        color: yellow;
    }
</style>

條件渲染

  • v-if , v-else 的用法欠拾,可使用變量,也可使用 === 表達(dá)式
  • v-if 和 v-show 的區(qū)別骗绕?
    • v-if 會直接銷毀和加載 DOM
    • v-show 修改 display 屬性為顯示或隱藏
  • v-if 和 v-show 的使用場景藐窄?
    • 頻繁切換顯示隱藏場景使用 v-show
    • 非頻繁切換顯示隱藏場景(如切換注冊/登錄)可使用 v-if

代碼演示

<template>
    <div>
        <p v-if="type === 'a'">A</p>
        <p v-else-if="type === 'b'">B</p>
        <p v-else>other</p>

        <p v-show="type === 'a'">A by v-show</p>
        <p v-show="type === 'b'">B by v-show</p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            type: 'a'
        }
    }
}
</script>

循環(huán)(列表)渲染

注意事項(xiàng)

  • v-for 可遍歷對象
  • key 不可亂寫(如 random 或者 index)
  • v-for 和 v-if 不建議一起使用!

代碼演示

<template>
    <div>
        <p>遍歷數(shù)組</p>
        <ul>
            <li v-for="(item, index) in listArr" :key="item.id">
                {{index}} - {{item.id}} - {{item.title}}
            </li>
        </ul>

        <p>遍歷對象</p>
        <ul >
            <li v-for="(val, key, index) in listObj" :key="key">
                {{index}} - {{key}} -  {{val.title}}
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    data() {
        return {
            flag: false,
            listArr: [
                { id: 'a', title: '標(biāo)題1' }, // 數(shù)據(jù)結(jié)構(gòu)中酬土,最好有 id 枷邪,方便使用 key
                { id: 'b', title: '標(biāo)題2' },
                { id: 'c', title: '標(biāo)題3' }
            ],
            listObj: {
                a: { title: '標(biāo)題1' },
                b: { title: '標(biāo)題2' },
                c: { title: '標(biāo)題3' },
            }
        }
    }
}
</script>

事件

  • event參數(shù),自定義參數(shù)
    • 在不傳自定義參數(shù)的情況下诺凡,event 對象可以直接在函數(shù)形參獲取
    • 傳入自定義參數(shù)情況下,需要將 $event 傳入
    • 此 event 是原生的 event 對象
  • 事件修飾符践惑,按鍵修飾符
    • stop 阻值點(diǎn)擊事件繼續(xù)傳播
    • prevent 提交事件不再重載頁面
    • v-on:click.stop.prevent 修飾符可以串聯(lián)使用
  • 【觀察】事件被綁定到哪里腹泌?
    • Vue 的事件是被掛載到當(dāng)前元素的

代碼演示

<template>
    <div>
        <p>{{num}}</p>
        <button @click="increment1">+1</button>
        <button @click="increment2(2, $event)">+2</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            num: 0
        }
    },
    methods: {
        increment1(event) {
            console.log('event', event, event.__proto__.constructor) // 是原生的 event 對象
            console.log(event.target)
            console.log(event.currentTarget) // 注意,事件是被注冊到當(dāng)前元素的尔觉,和 React 不一樣
            this.num++

            // 1. event 是原生的
            // 2. 事件被掛載到當(dāng)前元素
            // 和 DOM 事件一樣
        },
        increment2(val, event) {
            console.log(event.target)
            this.num = this.num + val
        },
        loadHandler() {
            // do some thing
        }
    },
    mounted() {
        window.addEventListener('load', this.loadHandler)
    },
    beforeDestroy() {
        //【注意】用 vue 綁定的事件凉袱,組建銷毀時會自動被解綁
        // 自己綁定的事件,需要自己銷毀U焱WㄋΑ!
        window.removeEventListener('load', this.loadHandler)
    }
}
</script>

表單

  • v-model 雙向數(shù)據(jù)綁定
  • 常見表單項(xiàng) textarea checkbox radio select
  • 修飾符 lazy(類似防抖效果) number(只能輸入數(shù)字) trim(去除兩邊空格)

代碼演示

<template>
    <div>
        <p>輸入框: {{name}}</p>
        <input type="text" v-model.trim="name"/>
        <input type="text" v-model.lazy="name"/>
        <input type="text" v-model.number="age"/>

        <p>多行文本: {{desc}}</p>
        <textarea v-model="desc"></textarea>
        <!-- 注意钉稍,<textarea>{{desc}}</textarea> 是不允許的5佣恪!贡未! -->

        <p>復(fù)選框 {{checked}}</p>
        <input type="checkbox" v-model="checked"/>

        <p>多個復(fù)選框 {{checkedNames}}</p>
        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
        <label for="jack">Jack</label>
        <input type="checkbox" id="john" value="John" v-model="checkedNames">
        <label for="john">John</label>
        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
        <label for="mike">Mike</label>

        <p>單選 {{gender}}</p>
        <input type="radio" id="male" value="male" v-model="gender"/>
        <label for="male">男</label>
        <input type="radio" id="female" value="female" v-model="gender"/>
        <label for="female">女</label>

        <p>下拉列表選擇 {{selected}}</p>
        <select v-model="selected">
            <option disabled value="">請選擇</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>

        <p>下拉列表選擇(多選) {{selectedList}}</p>
        <select v-model="selectedList" multiple>
            <option disabled value="">請選擇</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
    </div>
</template>

<script>
export default {
    data() {
        return {
            name: '吉良吉影',
            age: 33,
            desc: '自我介紹',

            checked: true,
            checkedNames: [],

            gender: 'male',

            selected: '',
            selectedList: []
        }
    }
}
</script>

其他

  • v-once 讓某元素標(biāo)簽只渲染一次
  • ref 寫在標(biāo)簽上可以通過 this.$refs 獲取操作 DOM 節(jié)點(diǎn)
    • ref 還可以寫在子組件上种樱,從而獲取子組件的引用

組件

props 和 $emit

  • props 父組件向子組件傳遞信息
  • $emit 子組件向父組件觸發(fā)一個事件
  • 實(shí)現(xiàn)父子組件之間通訊

父組件

<template>
    <div>
        <Input @add="addHandler"/>
        <List :list="list" @delete="deleteHandler"/>
    </div>
</template>

<script>
import Input from './Input'
import List from './List'

export default {
    components: {
        Input,
        List
    },
    data() {
        return {
            list: [
                {
                    id: 'id-1',
                    title: '標(biāo)題1'
                },
                {
                    id: 'id-2',
                    title: '標(biāo)題2'
                }
            ]
        }
    },
    methods: {
        addHandler(title) {
            this.list.push({
                id: `id-${Date.now()}`,
                title
            })
        },
        deleteHandler(id) {
            this.list = this.list.filter(item => item.id !== id)
        }
    },
    created() {
        console.log('index created')
    },
    mounted() {
        console.log('index mounted')
    },
    beforeUpdate() {
        console.log('index before update')
    },
    updated() {
        console.log('index updated')
    },
}
</script>

Input 組件

<template>
    <div>
        <input type="text" v-model="title"/>
        <button @click="addTitle">add</button>
    </div>
</template>

<script>
import event from './event'

export default {
    data() {
        return {
            title: ''
        }
    },
    methods: {
        addTitle() {
            // 調(diào)用父組件的事件
            this.$emit('add', this.title)

            // 調(diào)用自定義事件
            event.$emit('onAddTitle', this.title)

            this.title = ''
        }
    }
}
</script>

List 組件

<template>
    <div>
        <ul>
            <li v-for="item in list" :key="item.id">
                {{item.title}}

                <button @click="deleteItem(item.id)">刪除</button>
            </li>
        </ul>
    </div>
</template>

<script>
import event from './event'

export default {
    // props: ['list']
    props: {
        // prop 類型和默認(rèn)值
        list: {
            type: Array,
            default() {
                return []
            }
        }
    },
    data() {
        return {

        }
    },
    methods: {
        deleteItem(id) {
            this.$emit('delete', id)
        },
        addTitleHandler(title) {
            console.log('on add title', title)
        }
    },
    created() {
        console.log('list created')
    },
    mounted() {
        console.log('list mounted')

        // 綁定自定義事件
        event.$on('onAddTitle', this.addTitleHandler)
    },
    beforeUpdate() {
        console.log('list before update')
    },
    updated() {
        console.log('list updated')
    },
    beforeDestroy() {
        // 及時銷毀,否則可能造成內(nèi)存泄露
        event.$off('onAddTitle', this.addTitleHandler)
    }
}
</script>

自定義事件

  • 創(chuàng)建一個 event.js (如下圖)
  • 通過在 event 上綁定自定義事件俊卤,調(diào)用自定義事件實(shí)現(xiàn)兄弟組件之間通訊(上圖代碼所示)
// event.js
import Vue from 'vue'

export default new Vue()

生命周期

單個組件

生命周期圖示

帶有父子組件的生命周期

  • 初始化父子組件執(zhí)行順序

先觸發(fā)父元素嫩挤,然后子元素先進(jìn)行,父元素收尾消恍。

父beforeCreate => 父created => 父beforeMount => 子beforeCreate => 子created => 子beforeMount

=> 子mounted => 父mounted

先父組件創(chuàng)建虛擬dom岂昭,再子組件創(chuàng)建虛擬dom 。初始化先保證父組件初始化完再初始化子組件狠怨。(外 => 內(nèi))

然后子組件渲染约啊,再父組件渲染 邑遏。渲染先保證子組件渲染完再渲染父組件 (內(nèi) => 外)

最先開始創(chuàng)建的是最外層組件,但是最先創(chuàng)建完的是最內(nèi)層組件棍苹。 => 類似先進(jìn)后出(棧)无宿。

  • 刪除子組件觸發(fā)生命周期順序

先觸發(fā)父元素,然后子元素先進(jìn)行枢里,父元素收尾孽鸡。

父beforeUpdate => 子beforeDestroy => 子destroyed => 父updated

  • 更新子組件觸發(fā)生命周期順序

先觸發(fā)父元素,然后子元素先進(jìn)行栏豺,父元素收尾彬碱。

父beforeUpdate => 子beforeUpdate => 子updated => 父updated

首先是修改父組件的data,所以觸發(fā)父組件的beforeUpdate奥洼,它要把更新后數(shù)據(jù)再傳遞給給子組件巷疼,子組件更新props,因此再觸發(fā)子組件的beforeUpdate灵奖,緊接著渲染頁面觸發(fā)子組件的updated嚼沿,只有子組件渲染完頁面后,這個時候父組件也就渲染完瓷患,觸發(fā)父組件的updated骡尽。

Non-Props

  • 父組件向子組件傳值,子組件沒有通過 props 接收擅编,那么子組件會把該屬性變成子組件最外層的 DOM 上的一個屬性
  • 如果不希望發(fā)生此特性那么可以在子組件上加 一條屬性:inheritAttrs: false
  • 子組件可以通過 this.$attrs 手動獲取 non-props 屬性

插槽

  • slot 中使用的作用域的問題

    • 父模板里調(diào)用的數(shù)據(jù)屬性攀细,使用的都是父模板里的數(shù)據(jù)
    • 子模板里調(diào)用的數(shù)據(jù)屬性,使用的都是子模板里的數(shù)據(jù)
  • 具名插槽

    • 父組件傳遞時加上屬性 v-slot="..." 可簡寫為 #...
    • 子組件<slot name="..."></slot>
  • 作用域插槽

    • 代碼演示:

    • const app = Vue.createApp({
          template: `
              <List v-slot="slotProps">   // 可簡寫為 ES6 解構(gòu)形式 v-slot="{ item }", 則下面直接用 item 即可
                  <span>{{ slotProps.item }}</span>   // 2. slotProps.item 就是子組件傳入的數(shù)據(jù)
              </List>
          `
      })
      
      app.component('List', {
          data() { return { list: [1, 2, 3] } },
          template: `
              <div>
                  <slot v-for="item in list" :item=item />    // 1. 將item傳給父組件
              </div>
          `
      })
      
    • 分析上面代碼:

    • 父組件調(diào)子組件的時候傳入 slot 進(jìn)來

    • 子組件通過 :item=item 把數(shù)據(jù)傳給父組件

    • 作用域插槽解決了什么問題爱态?

      • 當(dāng)子組件渲染的內(nèi)容要由父組件決定的情況
      • 通過作用域插槽谭贪,可以讓使父組件調(diào)用子組件里的數(shù)據(jù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锦担,隨后出現(xiàn)的幾起案子俭识,更是在濱河造成了極大的恐慌,老刑警劉巖洞渔,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鱼的,死亡現(xiàn)場離奇詭異,居然都是意外死亡痘煤,警方通過查閱死者的電腦和手機(jī)凑阶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衷快,“玉大人宙橱,你說我怎么就攤上這事。” “怎么了师郑?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵环葵,是天一觀的道長。 經(jīng)常有香客問我宝冕,道長张遭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任地梨,我火速辦了婚禮菊卷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宝剖。我一直安慰自己洁闰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布万细。 她就那樣靜靜地躺著扑眉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赖钞。 梳的紋絲不亂的頭發(fā)上腰素,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音雪营,去河邊找鬼弓千。 笑死,一個胖子當(dāng)著我的面吹牛卓缰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砰诵,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼征唬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茁彭?” 一聲冷哼從身側(cè)響起总寒,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎理肺,沒想到半個月后摄闸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妹萨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年年枕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乎完。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡熏兄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摩桶,我是刑警寧澤桥状,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站硝清,受9級特大地震影響辅斟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芦拿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一士飒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧防嗡,春花似錦变汪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至他嫡,卻和暖如春番官,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钢属。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工徘熔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淆党。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓酷师,卻偏偏與公主長得像,于是被迫代替她去往敵國和親染乌。 傳聞我的和親對象是個殘疾皇子山孔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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