vue3知識(shí)點(diǎn)

Vue.js

核心是一個(gè)允許采用簡潔的模板語法來聲明式地將數(shù)據(jù)渲染進(jìn)DOM的系統(tǒng)
組件本質(zhì)上是一個(gè)具有預(yù)定義選項(xiàng)的實(shí)例
const app = vue.createApp({ ... }) // 在應(yīng)用中創(chuàng)建“全局”組件

// 創(chuàng)建 Vue 應(yīng)用實(shí)例
const app = Vue.createApp(...)

// 定義名為 todo-item 的新組件
app.component('todo-item', {
  template: `<li>This is a todo</li>`
})

// 掛載 Vue 應(yīng)用
app.mount(...)

Demo

const ComponentsApp = {
  data() {
    return {
      groceryList: [
        { id: 0, text: 'Vegetables' },
        { id: 1, text: 'Cheese' },
        { id: 2, text: 'Whatever else humans are supposed to eat' }
      ]
    }
  }
}
// 允許鏈?zhǔn)綄懛?// Vue.createApp({})
//  .component('SearchInput', SearchInputComponent)
//  .directive('focus', FocusDirective)
//  .use(LocalePlugin)

const app = Vue.createApp(ComponentsApp)
app.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`
})
app.mount('#components-app')
<div id="todo-list-app">
  <ol>
     <!--
      現(xiàn)在我們?yōu)槊總€(gè) todo-item 提供 todo 對(duì)象
      todo 對(duì)象是變量,即其內(nèi)容可以是動(dòng)態(tài)的。
      我們也需要為每個(gè)組件提供一個(gè)“key”,稍后再
      作詳細(xì)解釋。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      v-bind:key="item.id"
    ></todo-item>
  </ol>
</div>
一、根組件
  1. 傳遞給createApp的選項(xiàng)用于配置根組件。當(dāng)我們掛載應(yīng)用時(shí),該組件被用作渲染的起點(diǎn)
  2. *** 根組件與其他組件沒有什么不同,配置選項(xiàng)是一樣的,所對(duì)應(yīng)的組件實(shí)例 行為也是一樣的
  3. *** mount 返回的是根組件實(shí)例,不是應(yīng)用本身

Vue 應(yīng)用掛載到 <div id="app"></div>

const RootComponent = { 
  /* 選項(xiàng) */ 
}
const app = Vue.createApp(RootComponent)
const vm = app.mount('#app') 
二、生命周期
  1. 生命周期函數(shù)、選項(xiàng)property(元素屬性)或回調(diào)上不可使用箭頭函數(shù)。生命周期鉤子this上下文指向調(diào)用它的當(dāng)前活動(dòng)實(shí)例。
  2. 箭頭函數(shù)并沒有this,this作為變量一直向上級(jí)詞法作用域查找。直至找到為止,經(jīng)常導(dǎo)致Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之類的錯(cuò)誤。
  vue.createApp({
    data() {
      return { count: 1 }
    },
    created() {
      console.log('count is' + this.count) // => count is 1
    }
  })
image.png
三、模板語法

在底層的實(shí)現(xiàn)上,Vue將模板編譯成虛擬DOM渲染函數(shù)。結(jié)合響應(yīng)性系統(tǒng),Vue能夠智能地計(jì)算出最少需要重新渲染多少組件,并把DOM操作次數(shù)減到最少。
*** v-html不能復(fù)合局部模板,因?yàn)閂ue不是基于字符串的模板引擎,反之,對(duì)于用戶界面(UI),組件更適合作為可重用和可組合的基本單位
*** 動(dòng)態(tài)渲染任意的HTML是非常危險(xiǎn)的,因?yàn)楹苋菀讓?dǎo)致XSS攻擊

1. 文本插值使用雙大括號(hào){{ 變量 }}
2. 動(dòng)態(tài)渲染HTML使用v-html
  const RenderHtmlApp = {
    data() {
      return {
        rawHtml: '<span style="color: red">這幾個(gè)文字是紅色</span>'
      }
    }
  }
  Vue.createApp(RenderHtmlApp).mount('#example')
<div id="example">
  <p> v-html解析<span v-html="rawHtml"></span> </p>
</div>
3. 插值雙大括號(hào){{ 單個(gè)表達(dá)式 }}可以使用js表達(dá)式
{{ n + 1 }}
{{ ok ? 'Yes' : 'No' }}
{{ arrayData.split(',') }}
...
{{ var a = 1 }} // 不會(huì)生效, 這是語句,不是表達(dá)式
{{ if( ok ) { return message } }} // 流控制也不會(huì)生效
4. v- 指令職責(zé)是:當(dāng)表達(dá)式的值改變時(shí),將其產(chǎn)生的連帶影響,響應(yīng)式作用于DOM
5. 參數(shù)
<a v-on:click="doSomthing"> ... </a>
6. 動(dòng)態(tài)參數(shù)

*** 動(dòng)態(tài)參數(shù)預(yù)期是求出一個(gè)字符串,異常情況下為null。這個(gè)null會(huì)被顯性地用于移除綁定

// 若attrname的值為click
<a v-on:[attrname]="doSomthing">...</a> 
等價(jià)于
<a v-on:click="doSomthing">...</a>

*** 在 DOM 中使用模板時(shí) (直接在一個(gè) HTML 文件里撰寫模板),還需要避免使用大寫字符來命名鍵名,因?yàn)闉g覽器會(huì)把 attribute 名全部強(qiáng)制轉(zhuǎn)為小寫:

<!--
在 DOM 中使用模板時(shí)這段代碼會(huì)被轉(zhuǎn)換為 `v-bind:[someattr]`。
除非在實(shí)例中有一個(gè)名為“someattr”的 property,否則代碼不會(huì)工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
7. 縮寫

v-on

// 完整語法
<a v-on:click="doSomthing">...</a>
// 縮寫
<a @click="doSomthing">...</a>
// 動(dòng)態(tài)參數(shù)縮寫
<a @[attrname]="doSomthing">...</a>

v-bind

// 完整語法
<a v-bind:href="url">...</a>
// 縮寫
<a :href="url">...</a>
// 動(dòng)態(tài)參數(shù)縮寫
<a :[key]="url">...</a>
四、Data Property

vue自動(dòng)為methods綁定this,以便它始終指向組件實(shí)例。這將確保方法再用作事件監(jiān)聽或回調(diào)時(shí)保持正確的this。定義methods時(shí)應(yīng)避免使用箭頭函數(shù)

1. vue沒有內(nèi)置的防抖、節(jié)流,可以引用lodash

為了使組件實(shí)例彼此獨(dú)立,可以在生命周期鉤子created里添加防抖函數(shù)

app.component( 'save-button', {
    created() {
      // 使用lodash 防抖函數(shù)
      this.debouncedClick = _.debounce(this.click, 500)
    },
    unmounted() {
      // 移除組件時(shí),取消定時(shí)器
      this.debouncedClick.cancle()
    },
    methods: {
      click() {
        // ... 響應(yīng)事件...
      }
    },
    template: `
      <button @click='debouncedClick'> Save </button>
    `
  })
五、計(jì)算屬性、偵聽器
1.computed 計(jì)算屬性

computed:{ ... }計(jì)算屬性是基于它們的響應(yīng)依賴關(guān)系緩存的。

以下:如果data的值不發(fā)生改變,即使多次訪問computFun計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果,而不必再次執(zhí)行函數(shù)。如果不希望緩存,可用methods來代替

computed: {
  computFun() {
    return this.data == 1 ? '是' :'否'
  }
}

以下計(jì)算屬性將不再更新,因?yàn)镈ate.now()不是響應(yīng)式依賴

  computed: {
    now() {
      return Date.now()
    }
  }
2.watch 偵聽器

當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步 或 開銷較大的操作時(shí),watch方式最有用

六、條件渲染

v-if、v-else-if、v-else、v-show

1.v-if、v-else-if、v-else

v-if和v-for不推薦同時(shí)使用,如果一起使用了v-if的優(yōu)先級(jí)更高

<template>元素當(dāng)做不可見的包裹元素,在上面使用v-if。最終的渲染結(jié)果不包括<template>元素

<template v-if="ok">
 <p>渲染后template標(biāo)簽不存在</p>
</template>
 // ok為true, 渲染結(jié)果為
<p>渲染后template標(biāo)簽不存在</p>
2.v-show

v-show的元素始終會(huì)被渲染并保留在DOM中,v-show只是簡單地切換元素的CSS property display
**** v-show不支持<template>元素,也不支持v-else

3.v-if VS v-show
  • v-if是真正的條件渲染,因?yàn)樗鼤?huì)確保再切換過程中,條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇?code>銷毀和重建。
  • v-if也是惰性的:如果在初始渲染時(shí)條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r(shí),才會(huì)開始渲染條件塊。
  • v-show不管初始條件是什么,元素總是會(huì)被渲染,并且只是簡單地基于CSS進(jìn)行切換(樣式display控制的顯示與隱藏)
  • **** 一般而言,v-if具有更高的切換開銷,而v-show有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用v-show較好;如果在運(yùn)行時(shí)條件很少改變,則使用v-if較好
七、列表渲染

用v-for把一個(gè)數(shù)組對(duì)應(yīng)為一組元素

1.數(shù)組
  • item為迭代數(shù)組元素別名。index為索引。key作為Vue識(shí)別節(jié)點(diǎn)的一個(gè)通用機(jī)制,key需使用字符串或數(shù)值類型的值
  • v-for可以在template元素中使用

當(dāng)Vue正在更新使用v-for渲染的元素列表時(shí),它默認(rèn)使用“就地更新”的策略。如果數(shù)據(jù)項(xiàng)的順序被改變,Vue將不會(huì)移動(dòng)DOM元素來匹配數(shù)據(jù)項(xiàng)的順序,而是就地更新每個(gè)元素,并且確保它們?cè)诿總€(gè)索引位置正確渲染

v-for與v-if同時(shí)使用時(shí)建議使用以下寫法:

<template v-for="(item, index) in items" :key="item.id">
  <li v-if="!item.isShow">{{item.name}}</li>
  <li>{{item.name}}</li>
</template>
2.對(duì)象
  • value為value。name為key。index為索引
  • 會(huì)按照object.keys()結(jié)果遍歷對(duì)象,但是不能保證它在不同JavaScript引擎下的結(jié)果一致
<li v-for="(value, name, index) in myObject">
  {{ index }}. {{ name }}: {{ value }}
</li>
3.數(shù)組更新

變更方法:變更調(diào)用了這些方法的原始數(shù)組
替換數(shù)組:即非變更方法,不會(huì)變更原始數(shù)組,而總是返回一個(gè)新數(shù)組

由于 JavaScript 的限制,Vue 不能檢測數(shù)組和對(duì)象的變化。當(dāng)你直接修改了對(duì)象屬性的值,會(huì)發(fā)現(xiàn)只有數(shù)據(jù)改了,頁面內(nèi)容沒有更新。Vue將被偵聽數(shù)組的變更方法進(jìn)行了包裹,所以它們也將會(huì)觸發(fā)視圖更新。

  • 變更方法:
    push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 替換數(shù)組方法:
    filter()、concat() 、slice()
八、事件處理
1. @click監(jiān)聽點(diǎn)擊事件
<button @click="btnFun('click me', $event)">點(diǎn)擊事件</button>
...
methods: {
  btnFun(msg, event) {
    // doSomthing
  }
}
2. @click多事件處理器
<button @click="one($event), two($event)">處理多事件按鈕</button>
...
methods: {
  one(event) {
    // 第一個(gè)事件處理邏輯
  },
  two(event) {
    // 第二個(gè)事件處理邏輯
  }
}

3. 事件修飾符

.stop、.prevent、.capture、.self、.once、.passive

使用修飾符時(shí),順序很重要;相應(yīng)代碼會(huì)以同樣的順序產(chǎn)生

<!-- 阻止單擊事件繼續(xù)傳播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重載頁面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修飾符可以串聯(lián) -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修飾符 -->
<form @submit.prevent></form>

<!-- 添加事件監(jiān)聽器時(shí)使用事件捕獲模式 -->
<!-- 即內(nèi)部元素觸發(fā)的事件先在此處理,然后才交由內(nèi)部元素進(jìn)行處理 -->
<div @click.capture="doThis">...</div>

<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div @click.self="doThat">...</div>
<!-- 點(diǎn)擊事件將只會(huì)觸發(fā)一次 -->
<a @click.once="doThis"></a>
<!-- 滾動(dòng)事件的默認(rèn)行為 (即滾動(dòng)行為) 將會(huì)立即觸發(fā)   -->
<!-- 而不會(huì)等待 `onScroll` 完成                   -->
<!-- 這其中包含 `event.preventDefault()` 的情況   -->
<div @scroll.passive="onScroll">...</div>
4. 其它修飾符
  • 按鍵修飾符:.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right

直接將 KeyboardEvent.key 暴露的任意有效按鍵名轉(zhuǎn)換為 kebab-case 來作為修飾符

<!-- 只有在 `key` 是 `Enter` 時(shí)調(diào)用 `vm.submit()` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
  • 系統(tǒng)修飾符:.ctrl、.alt、.shift、.meta(在 Mac 系統(tǒng)鍵盤上,meta 對(duì)應(yīng) command 鍵 (?)。在 Windows 系統(tǒng)鍵盤 meta 對(duì)應(yīng) Windows 徽標(biāo)鍵 (?))
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
  • .exact 修飾符:.exact 修飾符允許你控制由精確的系統(tǒng)修飾符組合觸發(fā)的事件
<!-- 即使 Alt 或 Shift 被一同按下時(shí)也會(huì)觸發(fā) -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的時(shí)候才觸發(fā) -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 沒有任何系統(tǒng)修飾符被按下的時(shí)候才觸發(fā) -->
<button @click.exact="onClick">A</button>
  • 鼠標(biāo)按鈕修飾符:.left、.right、.middle
九、表單輸入綁定
  • v-model語法糖:可以在表單<input>、<textarea>、<select>等元素上創(chuàng)建雙向數(shù)據(jù)綁定。它負(fù)責(zé)監(jiān)聽用戶的輸入事件來更新數(shù)據(jù),并在某種極端場景下進(jìn)行一些特殊處理
  • v-model會(huì)忽略所有表單元素的value、checked、selected attribute的初始值而總是將當(dāng)前活動(dòng)實(shí)例的數(shù)據(jù)作為數(shù)據(jù)來源,應(yīng)該通過JavaScript在組件的data選項(xiàng)中聲明初始值
1. 值綁定
<!-- 當(dāng)選中時(shí),`picked` 為字符串 "a" -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` 為 true 或 false -->
<input type="checkbox" v-model="toggle" />

<!-- 當(dāng)選中第一個(gè)選項(xiàng)時(shí),`selected` 為字符串 "abc" -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>
<!-- 當(dāng)選中時(shí)vm.pick === vm.a-->
<input type="radio" v-model="pick" v-bind:value="a" />
2. 修飾符
  • .lazy:在默認(rèn)情況下,v-model在每次input事件觸發(fā)后將輸入框的值與數(shù)據(jù)進(jìn)行同步。添加.lazy修飾符,可以轉(zhuǎn)為change事件之后進(jìn)行同步
<!-- 在“change”時(shí)而非“input”時(shí)更新 -->
<input v-model.lazy="msg" />
  • .number:自動(dòng)將用戶的輸入值轉(zhuǎn)為數(shù)值類型
<input v-model.number="age" type="number" />
  • .trim: 自動(dòng)過濾用戶輸入的首位空白字符
<input v-model.trim="msg" />
十、組件基礎(chǔ)
  • 父組件通過props向子組件傳遞數(shù)據(jù)
  • 子組件通過調(diào)用內(nèi)建的$emit()并傳入事件名稱來觸發(fā)一個(gè)事件
<button @click="$emit('enlargeText', 0.1)">
  Enlarge text
</button>
...
methods: {
  onEnlargeText(enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}
1. 動(dòng)態(tài)組件
  • is:不同組件之間進(jìn)行動(dòng)態(tài)切換

以下currentTabComponent可以包括:已注冊(cè)的名字 或 一個(gè)組件的選項(xiàng)對(duì)象

<!-- 組件會(huì)在 `currentTabComponent` 改變時(shí)改變 -->
<component :is="currentTabComponent"></component>
  • 有些HTML元素,諸如<table>內(nèi)只能出現(xiàn)<tr>元素,可以使用is變通
// blog-post-row為 自定義組件
<table>
  <tr is="vue:blog-post-row"></tr> 
</table>
2. 屬性名稱 大小寫

HTML attribute 名不區(qū)分大小寫,因此瀏覽器將所有大寫字符解釋為小寫。這意味著當(dāng)你在 DOM 模板中使用時(shí),駝峰 prop 名稱和 event 處理器參數(shù)需要使用它們的 kebab-cased (橫線字符分隔) 等效

app.component('blog-post', {
  props: ['postTitle'],
  template: `
    <h3>{{ postTitle }}</h3>
  `
})
...
<blog-post post-title="hello!"></blog-post>
十一、組件注冊(cè)
1.全局注冊(cè): 在注冊(cè)以后可以用在任何新創(chuàng)建的組件實(shí)例模板中

app.component的第一個(gè)參數(shù)是組件名

const app = Vue.createApp({ ... })
app.component('my-component-name', {
  ...
})

...
<my-component-name></my-component-name>
2.局部注冊(cè): 在components選項(xiàng)中定義組件以后才可使用

局部注冊(cè)的組件在其子組件中不可使用

在 ComponentB 中可用ComponentA。舉例:

const ComponentA = {
  /* ... */
}

const ComponentB = {
  components: {
    'component-a': ComponentA
  }
  // ...
}

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  }
  // ...
}
十二、props:父組件向子組件傳值

props單向下綁定的數(shù)據(jù)流向。數(shù)據(jù)只能從父組件流向子組件,在子組件中不可修改prop

app.component('my-component', {
  props: {
    // 基礎(chǔ)的類型檢查 (`null` 和 `undefined` 會(huì)通過任何類型驗(yàn)證)
    propA: Number,
    // 多個(gè)可能的類型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 帶有默認(rèn)值的數(shù)字
    propD: {
      type: Number,
      default: 100
    },
    // 帶有默認(rèn)值的對(duì)象
    propE: {
      type: Object,
      // 對(duì)象或數(shù)組默認(rèn)值必須從一個(gè)工廠函數(shù)獲取
      default() {
        return { message: 'hello' }
      }
    },
    // 自定義驗(yàn)證函數(shù)
    propF: {
      validator(value) {
        // 這個(gè)值必須匹配下列字符串中的一個(gè)
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默認(rèn)值的函數(shù)
    propG: {
      type: Function,
      // 與對(duì)象或數(shù)組默認(rèn)值不同,這不是一個(gè)工廠函數(shù) —— 這是一個(gè)用作默認(rèn)值的函數(shù)
      default() {
        return 'Default function'
      }
    }
  }
})
  • type 還可以是一個(gè)自定義的構(gòu)造函數(shù)

用于驗(yàn)證author prop的值是否通過new Person創(chuàng)建的。舉例:

function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

...可以使用

app.component('blog-post', {
  props: {
    author: Person
  }
})
  • prop的大小寫命名
    HTML中的attribute名是大小寫不敏感的,所以瀏覽器會(huì)把所有的大寫字符解釋為小寫字符。這意味著當(dāng)你使用DOM中的模板時(shí),駝峰命名法的prop名需要使其等價(jià)的短橫線分割命名
const app = Vue.createApp({})

app.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

...

<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容