vue的一些注意點

Vue注意點

v-html

你的站點上動態渲染的任意 HTML 可能會很是危險,由於它很容易致使 XSS 攻擊。請只對可信內容使用 HTML 插值,毫不要對用戶提供的內容插值。html

利用標籤模板,過濾 HTML 字符串,防止用戶輸入惡意內容。vue

function SaferHTML(templateData) {
    let s = templateData[0];
    console.log(s);
    for (let i = 1; i < arguments.length; i++) {
        let arg = String(arguments[i]);

        // Escape special characters in the substitution.
        s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

        // Don't escape special characters in the template.
        s += templateData[i];
    }
    return s;
}

條件渲染

template不支持v-showes6

默認狀況下在切換dom時相同的結構會被複用,若是不須要複用,須要添加key數組

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="1">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="2">
</template>

checkbox

多個複選框。v-model須要綁定到一個數組app

//html
<div id='example-3'>
  <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>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>

//js
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})

多選時的select框同理dom

箭頭函數

不要在選項屬性或回調上使用箭頭函數,好比 created: () => console.log(this.a)
vm.$watch('a', newValue => this.myMethod())。由於箭頭函數是和父級上下文綁定在一塊兒的,this 不會是如你所預期的 Vue 實例,常常致使 Uncaught TypeError: Cannot read property of undefined
Uncaught TypeError: this.myMethod is not a function 之類的錯誤。ide

數組更新檢測

Vue 包含一組觀察數組的變異方法,因此它們也將會觸發視圖更新。這些方法以下:push()、pop()、shift()、unshift()、splice()、sort()、reverse()。函數

變異方法 (mutation method),顧名思義,會改變被這些方法調用的原始數組。相比之下,也有非變異 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 。這些不會改變原始數組,但老是返回一個新數組。當使用非變異方法時,能夠用新數組替換舊數組:post

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

注意事項

因爲 JavaScript 的限制,Vue 不能檢測如下變更的數組:性能

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是響應性的
vm.items.length = 2 // 不是響應性的

爲了解決第一類問題,如下兩種方式均可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸發狀態更新:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue) 

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

你也可使用 vm.$set 實例方法,該方法是全局方法 Vue.set 的一個別名:

vm.$set(vm.items, indexOfItem, newValue)

爲了解決第二類問題,你可使用 splice:

vm.items.splice(newLength)

==Vue.set可改成vm.$set==

對象更改檢測注意事項

仍是因爲 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 如今是響應式的

vm.b = 2
// `vm.b` 不是響應式的

對於已經建立的實例,Vue 不能動態添加根級別的響應式屬性。可是,可使用 Vue.set(object, key, value) 方法向嵌套對象添加響應式屬性。例如,對於:

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

你能夠添加一個新的 age 屬性到嵌套的 userProfile 對象:

Vue.set(vm.userProfile, 'age', 27)

若是須要爲已有對象賦予多個屬性:

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

刪除屬性用Vue.delete或者vm.$delete。

Vue.delete(vm.items,0);
//或者
vm.$delete(vm.items,0);

解析 DOM 模板時的注意事項

有些 HTML 元素,諸如 <ul>、<ol>、<table> 和 <select>,對於哪些元素能夠出如今其內部是有嚴格限制的。而有些元素,諸如 <li>、<tr> 和 <option>,只能出如今其它某些特定的元素內部。

這會致使咱們使用這些有約束條件的元素時遇到一些問題。例如:

<table>
  <blog-post-row></blog-post-row>
</table>

這個自定義組件 會被做爲無效的內容提高到外部,並致使最終渲染結果出錯。幸虧這個特殊的 is 特性給了咱們一個變通的辦法:

<table>
  <tr is="blog-post-row"></tr>
</table>

須要注意的是若是咱們從如下來源使用模板的話,這條限制是不存在的:

單個根元素

每一個組件必須只有一個根元素

<h3>{{ title }}</h3>
<div v-html="content"></div>

以上模板會報錯,將其包裹在一個父元素內便可解決

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

組件名大小寫

當組件名使用 kebab-case方式時,在引用這個自定義元素時必須使用 kebab-case
當組件名使用 PascalCase方式時,引用這個自定義元素時可以使用 kebab-case 或者 PascalCase

可是,直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case 是有效的

事件名

跟組件和 prop 不一樣,事件名不存在任何自動化的大小寫轉換。而是觸發的事件名須要徹底匹配監聽這個事件所用的名稱。

this.$emit('myEvent')

<my-component v-on:my-event="doSomething"></my-component>

以上監聽是沒法生效的,v-on 事件監聽器在 DOM 模板中會被自動轉換爲全小寫 (由於 HTML 是大小寫不敏感的)。所以,推薦始終使用 kebab-case 的事件名

事件處理

常規綁定方法

//html
<div id="example-2">
  <!-- `greet` 是在下面定義的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
//js
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 對象中定義方法
  methods: {
    greet: function (event) {
      // `this` 在方法裏指向當前 Vue 實例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

內聯 JavaScript 語句中調用方法

//html
<div id="example-3">
  <button v-on:click="say('hi', $event)">Say hi</button>
  <button v-on:click="say('what', $event)">Say what</button>
</div>
//js
new Vue({
  el: '#example-3',
  methods: {
    say: function (message, event) {
      alert(message)
    }
  }
})

v-model

<input v-model="searchText">
//等價於
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

給組件添加 v-model 屬性時,==默認會把 value 做爲組件的屬性,而後把 'input' 值做爲給組件綁定事件時的事件名==

可是在單選框、複選框等類型的輸入控件,須要的就不是默認的value特性以及input事件了,有兩種方法進行修改

html

<base-checkbox v-model="lovingVue"></base-checkbox>
  1. 修改v-model語法糖
Vue.component('base-checkbox', {
  props:['value']
  template: `
    <input
      type="checkbox"
      v-bind:checked="value"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
  1. 在 Vue 2.2 版本,你能夠在定義組件時經過 model 選項的方式來定製 prop/event:
Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

爲組件添加原生事件

爲v-on添加.native修飾符便可

<base-input v-on:focus.native="onFocus"></base-input>

特殊狀況: 若是使用focus監聽input元素,而且input元素被包裹在一個父元素中,.native監聽器將默認失敗

$attrs、$listeners、inheritAttrs

名詞解釋

$attrs--繼承全部的父組件屬性(除了prop傳遞的屬性、class 和 style )

inheritAttrs:默認值true,繼承全部的父組件屬性(除props的特定綁定)做爲普通的HTML特性應用在子組件的根元素上,若是你不但願組件的根元素繼承特性設置inheritAttrs: false,可是class屬性和style會繼承。

$listeners--屬性,它是一個對象,裏面包含了做用在這個組件上的全部監聽器,你就能夠配合 v-on="$listeners" 將全部的事件監聽器指向這個組件的某個特定的子元素。

代碼演示:

//HTML
<div id="app">
    <base-input v-model="a" placeholder="tip" label="name" class="a" :style="{color: 'red'}"></base-input>
</div>

//JS
Vue.component('base-input', {
    props: ['value'],
    template: `
    <label>
    {{$attrs.placeholder}}
    {{$attrs.label}}
      <input
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
        v-bind="$attrs">
    </label>
    `
});
var v = new Vue({
    el: '#app',
    data: {
        a: '123',
    }
});

由於inheritAttrs的默認值爲ture,因此組件的根元素label將繼承父組件的全部屬性(除了class、style和props傳遞的屬性);組件內的input則經過v-on="$attrs"綁定了父組件的屬性。

渲染結果爲:

<label placeholder="tip" label="name" class="a" style="color: red;">
    tip
    name
    <input placeholder="tip" label="name">
</label>

若將inheriAttrs值設爲false,
根元素label將不會繼承父組件的屬性。

<label class="a" style="color: red;">
    tip
    name
    <input placeholder="tip" label="name">
</label>

$attrs能夠打包父組件的屬性,一樣的,$listeners則打包父組件的事件

//html
<div id="app">
    <base-input @click="func" @focus="funf" v-model="a" placeholder="tip" label="name" class="a" :style="{color: 'red'}"></base-input>
</div>

//js
Vue.component('base-input', {
//  inheritAttrs: false,
    props: ['value'],
    template: `
    <label>
    {{$attrs.placeholder}}
    {{$attrs.label}}
      <input
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
        v-bind="$attrs"
        v-on="$listeners">
    </label>
    `
});
var v = new Vue({
    el: '#app',
    data: {
        a: '123',
    },
    methods: {
        func: function(){
            console.log('被點擊了');
        },
        funf: function(){
            console.log('得到焦點');
        }
    },
});

插槽

若是組件沒有包含一個 元素,則任何傳入它的內容都會被拋棄。

$nextTick()

若是數據變化後想獲取真實dom中的內容,須要等待頁面渲染完畢後再去獲取全部的dom操做最好放在nextTick中

slot插槽

若是組件模板沒有包含一個 元素,則任何傳入它的內容都會被拋棄。

<my-component>
    Your Profile
</my-component>

當有多個內容須要分配至相應插槽中,能夠將內容包裹在設置了slot特性的

//html
<my-component>
    <template slot="header">
        <h1 slot="header">這是標題</h1>
        <p slot="test">這是段落</p>
        <a href="baidu.com">百度</a>
    </template>
    <div>盒子</div>
</my-component>

<template id="my">
    <header>
        <slot name="header"></slot>
    </header>
    <slot></slot>
</template>

//js
my-component{
    template:'#my'
}

若是 沒有設置name屬性,或者設了name值爲「default」,name該插槽爲默認插槽,它將會把未匹配到插槽的內容統一分配至默認插槽中

//html
<my-component>
    <h1 slot="header">這是標題</h1>
    <p slot="test">這是段落</p>
    <a href="baidu.com">百度</a>
</my-component>

<template id="my">
    <slot name="header"></slot>
    <slot></slot>
</template>

//js
my-component{
    template:'#my'
}

上面代碼中,h1會被保存在name爲header的slot中,而p、a標籤將會被保存在默認插槽中。

插槽標籤內部加入內容能夠起到默認值效果,

<button type="submit">
  <slot>Submit</slot>
</button>

若是父組件爲這個插槽提供了內容,則默認的內容會被替換掉。

做用域插槽

//todo-list模板
<ul>
  <li
    v-for="todo in todos"
    v-bind:key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

假設咱們的todo-list組件被多個地方調用,而咱們但願能在不一樣的地方調用組件的時候,組件的todo.text不只限於以li的形式渲染,而是能以自定義的形式渲染,這時,做用域插槽能夠知足:

//html
<todo-list :todos="todos">
  <!-- 將 `slotProps` 定義爲插槽做用域的名字 -->
  <template slot-scope="slotProps">
    <li>{{slotProps.text}}</li>
  </template>
</todo-list>
//js
//todo-list模板
<ul>
    <slot v-for="todo in todos" :todo="todo" :key="todo.id">
      {{ todo.text }}
    </slot>
</ul>

首先,在todo-list模板中,將li替換爲slot,意味着slot具體被渲染成什麼將由html中的todo-list組件的內容決定;接下來,在todo-list組件內添加template標籤並設置slot-scope屬性來接收slot所綁定的todo屬性。就此,todo對象傳遞給了slotProps,todo-list組件內的li能夠隨意替代爲其餘標籤。

關於

咱們以前曾經在一個多標籤的界面中使用 is 特性來切換不一樣的組件:

<component :is="currentTabComponent"></component>

當在這些組件之間切換的時候,你有時會想保持這些組件的狀態,以免反覆重渲染致使的性能問題。這時,咱們在外圍包裹keep-alive便可

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>
相關文章
相關標籤/搜索