日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

(三)Vue使用

發布時間:2023/12/31 vue 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (三)Vue使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Vue使用

  • 概述
  • 面試題
  • Vue基本使用
      • 模板(指令、插值)
      • computed和watch
      • class和style
      • 條件渲染
      • 循環(列表)渲染
      • 事件
      • 表單
  • 組件
      • props和$emit
      • 組件間通訊-自定義事件
      • 生命周期
        • 單個組件
        • 父子組件
  • 高級特性
      • 自定義v-model
      • refs與$nextTick
      • slot
        • 基本使用
        • 作用域插槽
        • 具名插槽
      • 動態組件
      • 異步組件
      • keep-alive
      • mixin
        • mixin問題
  • Vuex使用
      • Vuex基本概念
      • 用于Vue組件
  • Vue-router使用
      • Vue-router路由模式
      • Vue-router路由配置

概述

基本使用,組件使用—常用,必須會
高級特性—不常用,但體現深度
Vuex和Vue-router的使用

面試題

v-show和v-if的區別
為何v-for中要用key
描述Vue組件生命周期(有父子組件的情況)
Vue組件如何通訊
描述組件渲染和更新的過程
雙向數據綁定v-model的實現原理

Vue基本使用

日常使用,必須掌握,面試必考(不一定會考)
梳理知識點,從冗長的文檔中摘出考點和重點
考察形式不限(參考后面的面試真題),但都在范圍之內

模板(指令、插值)

插值、表達式
指令、動態屬性
v-html:會有XSS風險,會覆蓋子組件

<template><div><p>文本插值 {{message}}</p><p>JS 表達式 {{ flag ? 'yes' : 'no' }} (只能是表達式,不能是 js 語句)</p><p :id="dynamicId">動態屬性 id</p><hr/><p v-html="rawHtml"><span>有 xss 風險</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不變則不會重新計算
watch如何深度監聽
watch監聽引用類型,拿不到oldVal

<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> <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) {// eslint-disable-next-lineconsole.log('watch name', oldVal, val) // 值類型,可正常拿到 oldVal 和 val},info: {handler(oldVal, val) {// eslint-disable-next-lineconsole.log('watch info', oldVal, val) // 引用類型,拿不到 oldVal 。因為指針相同,此時已經指向了新的 val},deep: true // 深度監聽}} } </script>

class和style

使用動態屬性
使用駝峰式寫法

<template><div><p :class="{ black: isBlack, yellow: isYellow }">使用 class</p><p :class="[black, yellow]">使用 class (數組)</p><p :style="styleData">使用 style</p></div> </template><script> export default {data() {return {isBlack: true,isYellow: true,black: 'black',yellow: 'yellow',styleData: {fontSize: '40px', // 轉換為駝峰式color: 'red',backgroundColor: '#ccc' // 轉換為駝峰式}}} } </script><style scoped>.black {background-color: #999;}.yellow {color: yellow;} </style>

條件渲染

v-if v-else的用法,可使用變量,也可以使用===表達式
v-if和v-show的區別
v-if和v-show的使用場景:切換頻繁使用v-show

v-show和v-if都能控制元素的顯示和隱藏。
v-show本質就是通過設置css中的display設置為none,控制隱藏,無論true或者false初始都會進行渲染,因此切換開銷比較小,初始開銷較大
v-if是動態的向DOM樹內添加或者刪除DOM元素,因為懶加載,初始為false時,不會渲染,因此初始渲染開銷較小,切換開銷比較大,要不停的銷毀和創建)
切換頻繁使用v-show

<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>

循環(列表)渲染

如何遍歷對象?—也可以用v-for
key的重要性。key不能亂寫(如random或者index)
v-for和v-if不能一起使用

因為v-for的優先級比v-if高,意味著v-if 將分別重復運行于每個 v-for 循環中,造成不必要的計算,影響性能
解決方法:將 v-if 置于外層元素 或在計算屬性中進行條件過濾

<template><div><p>遍歷數組</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: '標題1' }, // 數據結構中,最好有 id ,方便使用 key{ id: 'b', title: '標題2' },{ id: 'c', title: '標題3' }],listObj: {a: { title: '標題1' },b: { title: '標題2' },c: { title: '標題3' },}}} } </script>

事件

event參數,自定義參數
事件修飾符,按鍵修飾符
【觀察】事件被綁定到哪里

<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) {// eslint-disable-next-lineconsole.log('event', event, event.__proto__.constructor) // 是原生的 event 對象// eslint-disable-next-lineconsole.log(event.target)// eslint-disable-next-lineconsole.log(event.currentTarget) // 注意,事件是被注冊到當前元素的,和 React 不一樣this.num++// 1. event 是原生的// 2. 事件被掛載到當前元素// 和 DOM 事件一樣},increment2(val, event) {// eslint-disable-next-lineconsole.log(event.target)this.num = this.num + val},loadHandler() {// do some thing}},mounted() {window.addEventListener('load', this.loadHandler)},beforeDestroy() {//【注意】用 vue 綁定的事件,組建銷毀時會自動被解綁// 自己綁定的事件,需要自己銷毀!!!window.removeEventListener('load', this.loadHandler)} } </script>


表單

v-model
常見表單項textarea checkbox radio select
修飾符lazy number trim

當添加.lazy修飾符之后,相當于 雙向數據綁定不起作用了,主要用于控制數據同步的時機,改變input框中的內容并不會使數據發生變化,當輸入框失去焦點后觸發change事件,數據才更新

<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> 是不允許的!!! --><p>復選框 {{checked}}</p><input type="checkbox" v-model="checked"/><p>多個復選框 {{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: 18,desc: '自我介紹',checked: true,checkedNames: [],gender: 'male',selected: '',selectedList: []}} } </script>

組件

props和$emit

組件間通訊-自定義事件

//index.vue <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: '標題1'},{id: 'id-2',title: '標題2'}]}},methods: {addHandler(title) {this.list.push({id: `id-${Date.now()}`,title})},deleteHandler(id) {this.list = this.list.filter(item => item.id !== id)}},created() {// eslint-disable-next-lineconsole.log('index created')},mounted() {// eslint-disable-next-lineconsole.log('index mounted')},beforeUpdate() {// eslint-disable-next-lineconsole.log('index before update')},updated() {// eslint-disable-next-lineconsole.log('index updated')}, } </script> //Input.vue <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() {// 調用父組件的事件this.$emit('add', this.title)// 調用自定義事件event.$emit('onAddTitle', this.title)this.title = ''}} } </script> //event.js import Vue from 'vue'export default new Vue() //List.vue <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 類型和默認值list: {type: Array,default() {return []}}},data() {return {}},methods: {deleteItem(id) {this.$emit('delete', id)},addTitleHandler(title) {// eslint-disable-next-lineconsole.log('on add title', title)}},created() {// eslint-disable-next-lineconsole.log('list created')},mounted() {// eslint-disable-next-lineconsole.log('list mounted')// 綁定自定義事件event.$on('onAddTitle', this.addTitleHandler)},beforeUpdate() {// eslint-disable-next-lineconsole.log('list before update')},updated() {// eslint-disable-next-lineconsole.log('list updated')},beforeDestroy() {// 及時銷毀,否則可能造成內存泄露event.$off('onAddTitle', this.addTitleHandler)} } </script>

生命周期

單個組件

  • 掛載階段(beforeCreate、created、beforeMount、mounted)
  • 更新階段(beforeUpdate、updated)
  • 銷毀階段(beforeDestory、destroyed )


created和mounted區別
created把vue示例給初始化,只是存在js內存模型的內存變量而已,并沒有開始渲染;
mounted組件真正在網頁上匯聚完成了,頁面渲染完成了

beforeDestory上可以做什么
解除綁定,銷毀子組件以及事件監聽器

父子組件



創建初始化vue實例是從外到內,只有父組件初始化完才能初始化子組件
渲染是從內到外,只有把子組件渲染完父組件才能渲染完
beforeUpdate:更新的時候父組件的data首先被修改,首先執行beforeUpdate
updated:只有子組件更新完了父組件才能更新完

渲染過程:父組件掛載完成一定是等子組件都掛載完成后,才算是父組件掛載完,所以父組件的mounted在子組件mouted之后。父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

子組件更新過程:
影響到父組件: 父beforeUpdate -> 子beforeUpdate->子updated -> 父updated
不影響父組件: 子beforeUpdate -> 子updated

父組件更新過程:
影響到子組件: 父beforeUpdate -> 子beforeUpdate->子updated -> 父updated
不影響子組件: 父beforeUpdate -> 父updated

銷毀過程:父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

不管是哪種情況,都一定是父組件等待子組件完成后,才會執行自己對應完成的鉤子

高級特性

//index.vue <template><div><p>vue 高級特性</p><hr><!-- 自定義 v-model --><!-- <p>{{name}}</p><CustomVModel v-model="name"/> --><!-- nextTick --><!-- <NextTick/> --><!-- slot --><!-- <SlotDemo :url="website.url">{{website.title}}</SlotDemo> --><!-- <ScopedSlotDemo :url="website.url"><template v-slot="slotProps">{{slotProps.slotData.title}}</template></ScopedSlotDemo> --><!-- 動態組件 --><!-- <component :is="NextTickName"/> --><!-- 異步組件 --><!-- <FormDemo v-if="showFormDemo"/><button @click="showFormDemo = true">show form demo</button> --><!-- keep-alive --><!-- <KeepAlive/> --><!-- mixin --><MixinDemo/></div> </template><script> // import CustomVModel from './CustomVModel' // import NextTick from './NextTick' // import SlotDemo from './SlotDemo' // import ScopedSlotDemo from './ScopedSlotDemo' // import KeepAlive from './KeepAlive' import MixinDemo from './MixinDemo'export default {components: {// CustomVModel// NextTick// SlotDemo,// ScopedSlotDemo,// FormDemo: () => import('../BaseUse/FormDemo'),// KeepAliveMixinDemo},data() {return {name: '雙越',website: {url: 'http://imooc.com/',title: 'imooc',subTitle: '程序員的夢工廠'},// NextTickName: "NextTick",showFormDemo: false}} } </script>

自定義v-model

//index.vue <template><div><!-- 自定義 v-model --><p>{{name}}</p><CustomVModel v-model="name"/></div> </template><script> import CustomVModel from './CustomVModel'export default {components: {CustomVModel},data() {return {name: '雙越',}} } </script> //CustomVModel.vue <template><!-- 例如:vue 顏色選擇 --><input type="text":value="text1"@input="$emit('change1', $event.target.value)"><!--1. 上面的 input 使用了 :value 而不是 v-model2. 上面的 change1 和 model.event 要對應起來3. text1 屬性對應起來--> </template><script> export default {model: {prop: 'text1', // 對應 props text1event: 'change1'},props: {text1: String,default() {return ''}} } </script>

refs與$nextTick

Vue是異步渲染(原理部分會詳細講解)
data改變之后,DOM不會立刻渲染
$nextTick會在DOM渲染之后被處罰,以獲取最新DOM節點

//index.vue <template><div><!-- nextTick --><NextTick/></div> </template><script> import NextTick from './NextTick'export default {components: {NextTick},data() {return {}} } </script> //NextTick.vue <template><div id="app"><ul ref="ul1"><li v-for="(item, index) in list" :key="index">{{item}}</li></ul><button @click="addItem">添加一項</button></div> </template><script> export default {name: 'app',data() {return {list: ['a', 'b', 'c']}},methods: {addItem() {this.list.push(`${Date.now()}`)this.list.push(`${Date.now()}`)this.list.push(`${Date.now()}`)// 1. 異步渲染,$nextTick 待 DOM 渲染完再回調// 3. 頁面渲染時會將 data 的修改做整合,多次 data 修改只會渲染一次this.$nextTick(() => {// 獲取 DOM 元素const ulElem = this.$refs.ul1// eslint-disable-next-lineconsole.log( ulElem.childNodes.length ) //沒有$nextTick返回3,6,有返回6,9})}} } </script>

slot

基本使用

//index.vue <template><div><!-- slot --><SlotDemo :url="website.url">{{website.title}}</SlotDemo></div> </template><script> import SlotDemo from './SlotDemo'export default {components: {SlotDemo},data() {return {website: {url: 'http://imooc.com/',title: 'imooc',subTitle: '程序員的夢工廠'},}} } </script> //SlotDemo.vue <template><a :href="url"><slot>默認內容,即父組件沒設置內容時,這里顯示</slot></a> </template><script> export default {props: ['url'],data() {return {}} } </script>

作用域插槽

//index.vue <template><div><ScopedSlotDemo :url="website.url"><template v-slot="slotProps">{{slotProps.slotData.title}}</template></ScopedSlotDemo></div> </template><script> import ScopedSlotDemo from './ScopedSlotDemo'export default {components: {ScopedSlotDemo},data() {return {website: {url: 'http://imooc.com/',title: 'imooc',subTitle: '程序員的夢工廠'},}} } </script> //ScopedSlotDemo.vue <template><a :href="url"><slot :slotData="website">{{website.subTitle}} <!-- 默認值顯示 subTitle ,即父組件不傳內容時 --></slot></a> </template><script> export default {props: ['url'],data() {return {website: {url: 'http://wangEditor.com/',title: 'wangEditor',subTitle: '輕量級富文本編輯器'}}} } </script>

具名插槽

動態組件

:is="component-name"用法
需要根據數據,動態渲染的場景,即組件類型不確定

比如一個新聞詳情頁,可能包含text、image、video組件,而且排序展示可能不一致

//index.vue <template><div><!-- 動態組件 --><!-- <component :is="NextTickName"/> --><div v-for="(val,key) in newsData" :key="key"><component :is="val.tye"/></div></div> </template><script> import ScopedSlotDemo from './ScopedSlotDemo'export default {components: {ScopedSlotDemo},data() {return {//NextTickName: "NextTick",newsData:[1:{type:'text},2:{type:'text},3:{type:'image},]}} } </script>

異步組件

import()函數
按需加載,異步加載大組件

//index.vue <template><div><!-- 異步組件 --><FormDemo v-if="showFormDemo"/><button @click="showFormDemo = true">show form demo</button></div> </template><script>export default {components: {FormDemo: () => import('../BaseUse/FormDemo')},data() {return {showFormDemo: false}} } </script>

keep-alive

緩存組件
頻繁切換,不需要重復渲染
Vue常見性能優化

//index.vue <template><div><!-- keep-alive --><KeepAlive/></div> </template><script> import KeepAlive from './KeepAlive' export default {components: {KeepAlive},data() {return {showFormDemo: false}} } </script> //KeepAlive.vue <template><div><button @click="changeState('A')">A</button><button @click="changeState('B')">B</button><button @click="changeState('C')">C</button><keep-alive> <!-- tab 切換 --><KeepAliveStageA v-if="state === 'A'"/> <!-- v-show --><KeepAliveStageB v-if="state === 'B'"/><KeepAliveStageC v-if="state === 'C'"/></keep-alive></div> </template><script> import KeepAliveStageA from './KeepAliveStateA' import KeepAliveStageB from './KeepAliveStateB' import KeepAliveStageC from './KeepAliveStateC'export default {components: {KeepAliveStageA,KeepAliveStageB,KeepAliveStageC},data() {return {state: 'A'}},methods: {changeState(state) {this.state = state}} } </script> //KeepAliveStateA.vue <template><p>state A</p> </template><script> export default {mounted() {// eslint-disable-next-lineconsole.log('A mounted')},destroyed() {// eslint-disable-next-lineconsole.log('A destroyed')} } </script> //KeepAliveStateB.vue <template><p>state B</p> </template><script> export default {mounted() {// eslint-disable-next-lineconsole.log('B mounted')},destroyed() {// eslint-disable-next-lineconsole.log('B destroyed')} } </script> //KeepAliveStateC.vue <template><p>state C</p> </template><script> export default {mounted() {// eslint-disable-next-lineconsole.log('C mounted')},destroyed() {// eslint-disable-next-lineconsole.log('C destroyed')} } </script>

點擊A-B-C-A-B-C
未加keep-alive前

加keep-alive后,離開不會destroyed,再次加載不會mounted

mixin

多個組件有相同的邏輯,抽離出來
mixin并不是完美的解決方案,會有一些問題
Vue 3 提出的Composition API旨在解決這些問題

//index.vue <template><div><!-- mixin --><MixinDemo/></div> </template><script> import MixinDemo from './MixinDemo' export default {components: {MixinDemo },data() {return {}} } </script> //MixinDemo.vue <template><div><p>{{name}} {{major}} {{city}}</p><button @click="showName">顯示姓名</button></div> </template><script> import myMixin from './mixin'export default {mixins: [myMixin], // 可以添加多個,會自動合并起來data() {return {name: '雙越',major: 'web 前端'}},methods: {},mounted() {// eslint-disable-next-lineconsole.log('component mounted', this.name)} } </script> //mixin.js export default {data() {return {city: '北京'}},methods: {showName() {// eslint-disable-next-lineconsole.log(this.name)}},mounted() {// eslint-disable-next-lineconsole.log('mixin mounted', this.name)} }

mixin問題

變量來源不明確,不利于閱讀
多mixin可能會造成命名沖突
mixin和組件可能出現多對多的關系,復雜度較高

Vuex使用

面試考點并不多(因為熟悉Vue之后,vuex沒有難度)
但基本概念,基本使用和API必須掌握
可能會考察state的數據結構設計(后面會講)

Vuex基本概念

state
getters
action
mutation
異步操作在Actions里進行

用于Vue組件

dispatch
commit
mapState
mapGetters
mapActions
mapMutations

Vuex 是專門為 Vue.js 設計的狀態管理庫,簡單地說就是采用全局單例模式,將組件的共享狀態抽離出來管理,使組件樹中的每一個位置都可以獲取共享的狀態(變量)或者觸發行為。實現響應式的全局變量

state–狀態,在store實例中注冊state;在組件中使用store.state訪問

getters–類似計算屬性,對store中某個屬性相同的處理操作抽出出來,做了一個公共的處理,組件中通過store.getters調用

action–異步更改狀態,參數有context和payload,context.state獲取store變量,context.commit觸發mutation,提交mutation去修改state,組件中使用this.store.dispatch調用

mutation–更改store中狀態的唯一方法,參數有state和payload,不能包含異步操作,組件中使用this.$store.commit調用

輔助函數:mapState、mapMutations、mapGetters、mapActions,它們的使用我們可以配合ES6的展開運算符將其與局部計算屬性或方法混合使用

import {mapState、mapMutations、mapGetters、mapActions} from ‘vuex’ compoted:{ ...mapState({}) } compoted:{ ...mapGetters({}) } methods:{ ...mapActions({}) } methods:{ ...mapMutations({}) }

Vue-router使用

面試考點并不多(前提是熟悉Vue)
路由模式(hash、H5 history)
路由配置(動態路由、懶加載)

Vue-router路由模式

hash模式(默認),如http://abc.com/#/user/10
H5 history模式,如http://abc.com/user/20
后者需要server端支持,因此無特殊需求可選擇前者

H5 history模式404不會跳轉,需要配置404情況

Vue-router路由配置


總結

以上是生活随笔為你收集整理的(三)Vue使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。