vue入門

1. 生命周期

我們先來(lái)看下圖:


image.png

我們來(lái)解釋一下上圖的各個(gè)階段:

beforeCreate: vue實(shí)例進(jìn)行基礎(chǔ)初始化時(shí)
created:實(shí)例初始化完成時(shí)
beforeMount:模板與數(shù)據(jù)結(jié)合掛載到頁(yè)面之前
beforeUpdate:數(shù)據(jù)發(fā)生改變,但并未渲染之前
updated:數(shù)據(jù)發(fā)生改變,并渲染之后
mounted:頁(yè)面掛載之后
beforeDestroy:組件銷毀之前
destroyed:銷毀組件之后

activated: keep-alive 組件激活時(shí)調(diào)用。該鉤子在服務(wù)器端渲染期間不被調(diào)用。
deactivated:keep-alive 組件停用時(shí)調(diào)用。該鉤子在服務(wù)器端渲染期間不被調(diào)用。
errorCaptured:2.5.0+ 新增,當(dāng)捕獲一個(gè)來(lái)自子孫組件的錯(cuò)誤時(shí)被調(diào)用。此鉤子會(huì)收到三個(gè)參數(shù):錯(cuò)誤對(duì)象、發(fā)生錯(cuò)誤的組件實(shí)例以及一個(gè)包含錯(cuò)誤來(lái)源信息的字符串。此鉤子可以返回 false 以阻止該錯(cuò)誤繼續(xù)向上傳播。

2. computed計(jì)算屬性

計(jì)算屬性在computed:{}中聲明,不需要在data中聲明,當(dāng)data中沒(méi)有時(shí)會(huì)自動(dòng)來(lái)計(jì)算屬性中找。寫法取下:

computer: {
  aaa: {
    get:function() {
        // 讀取該方法內(nèi)容時(shí)
    },
    set:function(value) {
        // 設(shè)置該方法時(shí),即給該方法重新賦值時(shí)
    }
}

3. 偵聽(tīng)屬性

來(lái)看下watch的作用,當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作時(shí),這個(gè)方式是最有用的。來(lái)看演示代碼:

<p>
    Ask a yes/no question:
    <input v-model="question">
</p>
<p>{{ answer }}</p>

data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
    // 如果 `question` 發(fā)生改變,這個(gè)函數(shù)就會(huì)運(yùn)行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
},

4. 樣式綁定

方法1: 對(duì)象形式

// 當(dāng)isactive為true時(shí)存在active類名
<div v-bind:class="{ active: isActive }"></div>

// 傳入多個(gè)class
<div
  class="static"
  v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
  isActive: true,
  hasError: false
}

// 綁定的數(shù)據(jù)對(duì)象不必內(nèi)聯(lián)定義在模板里:

<div v-bind:class="classObject"></div>

data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

// 也可以在這里綁定一個(gè)返回對(duì)象的計(jì)算屬性。

<div v-bind:class="classObject"></div>

data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

方法2: 數(shù)組形式

<div v-bind:class="[isactive]"></div>
data{
    isactive:"active"
}

// 動(dòng)態(tài)切換
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

// 在數(shù)組中加入對(duì)象語(yǔ)法
<div v-bind:class="[{ active: isActive }, errorClass]"></div>

方法3: 綁定style樣式

<div v-bind:style="styleObj"></div>
data{
    styleObj:{
        color:"black"
    }
}

<div v-bind:style="[styleObj,{fontSize:'20px'}]"></div>
data{
    styleObj:{
        color:"black"
    }
}

// 綁定多個(gè)值的數(shù)組,這樣寫只會(huì)渲染數(shù)組中最后一個(gè)被瀏覽器支持的值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

5. 條件渲染

5.1 v-if

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

如果想切換多個(gè)元素,我們使用template包裹即可

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

vue會(huì)復(fù)用v-if中相同的組件,如果要避免,可設(shè)置key,如下:

<div v-if=“show”>
    <input key=“username” />
</div>
<div v-else>
    <input key=“password” />
</div>

5.2 v-show與v-if區(qū)別

  1. v-show 的元素始終會(huì)被渲染并保留在 DOM 中。v-show 只是簡(jiǎn)單地切換元素的 CSS 屬性 display。
  2. v-show 不支持 <template> 元素,也不支持 v-else。
  3. v-if 是“真正”的條件渲染,因?yàn)樗鼤?huì)確保在切換過(guò)程中條件塊內(nèi)的事件監(jiān)聽(tīng)器和子組件適當(dāng)?shù)乇讳N毀和重建。
  4. v-if 也是惰性的:如果在初始渲染時(shí)條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r(shí),才會(huì)開(kāi)始渲染條件塊。v-show 就簡(jiǎn)單得多——不管初始條件是什么,元素總是會(huì)被渲染,并且只是簡(jiǎn)單地基于 CSS 進(jìn)行切換。
  5. 一般來(lái)說(shuō),v-if 有更高的切換開(kāi)銷,而 v-show 有更高的初始渲染開(kāi)銷。因此,如果需要非常頻繁地切換,則使用 v-show 較好;如果在運(yùn)行時(shí)條件很少改變,則使用 v-if 較好。

5.3 v-show與v-for一起使用

不推薦同時(shí)使用 v-ifv-for。當(dāng) v-ifv-for 一起使用時(shí),v-for 具有比 v-if 更高的優(yōu)先級(jí)。

6. 列表渲染

6.1 數(shù)組的v-for

<ul id="example-2">
  <li v-for="(item, index) in items" :key="item.id">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

可以用 of 替代 in 作為分隔符,因?yàn)樗亲罱咏?JavaScript 迭代器的語(yǔ)法,遍歷沒(méi)有in深,節(jié)省性能

6.2 對(duì)象的v-for

// 第二個(gè)參數(shù)為鍵名,第三個(gè)參數(shù)為索引
<ul id="v-for-object" class="demo">
 <li v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</li>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

在遍歷對(duì)象時(shí),是按 Object.keys() 的結(jié)果遍歷,但是不能保證它的結(jié)果在不同的 JavaScript 引擎下是一致的。

6.3 注意事項(xiàng)

由于 JavaScript 的限制,Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:

  1. 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如:vm.items[indexOfItem] = newValue
  2. 當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如:vm.items.length = newLength

舉個(gè)例子:

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

為了解決第一類問(wèn)題,以下兩種方式都可以實(shí)現(xiàn)和 vm.items[indexOfItem] = newValue 相同的效果,同時(shí)也將觸發(fā)狀態(tài)更新:

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

你也可以使用 vm.$set 實(shí)例方法,該方法是全局方法 Vue.set 的一個(gè)別名:

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

為了解決第二類問(wèn)題,你可以使用 splice

vm.items.splice(newLength)

還有如下方法:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()

6.4 對(duì)象更改檢測(cè)注意事項(xiàng)

還是由于 JavaScript 的限制,Vue 不能檢測(cè)對(duì)象屬性的添加或刪除:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 現(xiàn)在是響應(yīng)式的

vm.b = 2
// `vm.b` 不是響應(yīng)式的

對(duì)于已經(jīng)創(chuàng)建的實(shí)例,Vue 不能動(dòng)態(tài)添加根級(jí)別的響應(yīng)式屬性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套對(duì)象添加響應(yīng)式屬性。例如,對(duì)于:

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

你可以添加一個(gè)新的 age 屬性到嵌套的 userProfile 對(duì)象:

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

你還可以使用 vm.$set 實(shí)例方法,它只是全局 Vue.set 的別名:

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

有時(shí)你可能需要為已有對(duì)象賦予多個(gè)新屬性,比如使用 Object.assign() 或 _.extend()。在這種情況下,你應(yīng)該用兩個(gè)對(duì)象的屬性創(chuàng)建一個(gè)新的對(duì)象。所以,如果你想添加新的響應(yīng)式屬性,不要像這樣:

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

你應(yīng)該這樣做:

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

6.5 顯示過(guò)濾/排序結(jié)果

有時(shí),我們想要顯示一個(gè)數(shù)組的過(guò)濾或排序副本,而不實(shí)際改變或重置原始數(shù)據(jù)。在這種情況下,可以創(chuàng)建返回過(guò)濾或排序數(shù)組的計(jì)算屬性。

例如:

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

在計(jì)算屬性不適用的情況下 (例如,在嵌套 v-for 循環(huán)中) 你可以使用一個(gè) method 方法:

<li v-for="n in even(numbers)">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

6.6 一段取值范圍的 v-for

v-for 也可以取整數(shù)。在這種情況下,它將重復(fù)多次模板。

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

結(jié)果:

1 2 3 4 5 6 7 8 9 10

6.7 v-for on a <template>

類似于 v-if,你也可以利用帶有 v-for<template> 渲染多個(gè)元素。比如:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

6.8 v-for with v-if

不推薦同時(shí)使用 v-ifv-for。當(dāng)它們處于同一節(jié)點(diǎn),v-for 的優(yōu)先級(jí)比 v-if 更高,這意味著 v-if 將分別重復(fù)運(yùn)行于每個(gè) v-for 循環(huán)中。當(dāng)你想為僅有的一些項(xiàng)渲染節(jié)點(diǎn)時(shí),這種優(yōu)先級(jí)的機(jī)制會(huì)十分有用,如下:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

上面的代碼只傳遞了未完成的 todos。

而如果你的目的是有條件地跳過(guò)循環(huán)的執(zhí)行,那么可以將 v-if 置于外層元素 (或 <template>)上。如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

6.9 一個(gè)組件的 v-for

在自定義組件里,你可以像任何普通元素一樣用 v-for 。

<my-component v-for="item in items" :key="item.id"></my-component>

2.2.0+ 的版本里,當(dāng)在組件中使用 v-for 時(shí),key 現(xiàn)在是必須的。

然而,任何數(shù)據(jù)都不會(huì)被自動(dòng)傳遞到組件里,因?yàn)榻M件有自己獨(dú)立的作用域。為了把迭代數(shù)據(jù)傳遞到組件里,我們要用 props

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>

不自動(dòng)將 item 注入到組件里的原因是,這會(huì)使得組件與 v-for 的運(yùn)作緊密耦合。明確組件數(shù)據(jù)的來(lái)源能夠使組件在其他場(chǎng)合重復(fù)使用。
下面是一個(gè)簡(jiǎn)單的 todo list 的完整例子:

<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Add a todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed the cat"
    >
    <button>Add</button>
  </form>
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>

注意這里的 is="todo-item" 屬性。這種做法在使用 DOM 模板時(shí)是十分必要的,因?yàn)樵?<ul> 元素內(nèi)只有 <li> 元素會(huì)被看作有效內(nèi)容。這樣做實(shí)現(xiàn)的效果與 <todo-item> 相同,但是可以避開(kāi)一些潛在的瀏覽器解析錯(cuò)誤。查看

Vue.component('todo-item', {
  template: '
    <li>
      {{ title }}
      <button v-on:click="$emit(\'remove\')">Remove</button>
    </li>
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Do the dishes',
      },
      {
        id: 2,
        title: 'Take out the trash',
      },
      {
        id: 3,
        title: 'Mow the lawn'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})

7. 事件處理

7.1 ## 內(nèi)聯(lián)處理器中的方法

如果需要在內(nèi)聯(lián)語(yǔ)句處理器中訪問(wèn)原始的 DOM 事件??梢杂锰厥庾兞?$event 把它傳入方法:

<button v-on:click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>
// ...
methods: {
  warn: function (message, event) {
    // 現(xiàn)在我們可以訪問(wèn)原生事件對(duì)象
    if (event) event.preventDefault()
    alert(message)
  }
}

7.2 事件修飾符

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

<!-- 提交事件不再重載頁(yè)面 -->
<form v-on:submit.prevent="onSubmit"></form>

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

<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>

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

<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>

<!-- 點(diǎn)擊事件將只會(huì)觸發(fā)一次 -->
<a v-on:click.once="doThis"></a>

<!-- 滾動(dòng)事件的默認(rèn)行為 (即滾動(dòng)行為) 將會(huì)立即觸發(fā) -->
<!-- 而不會(huì)等待 `onScroll` 完成  -->
<!-- 這其中包含 `event.preventDefault()` 的情況 -->
<div v-on:scroll.passive="onScroll">...</div>

使用修飾符時(shí),順序很重要;相應(yīng)的代碼會(huì)以同樣的順序產(chǎn)生。因此,用
v-on:click.prevent.self 會(huì)阻止所有的點(diǎn)擊,而
v-on:click.self.prevent 只會(huì)阻止對(duì)元素自身的點(diǎn)擊。

不要把 .passive 和 .prevent 一起使用,因?yàn)?.prevent 將會(huì)被忽略,同時(shí)瀏覽器可能會(huì)向你展示一個(gè)警告。請(qǐng)記住,.passive 會(huì)告訴瀏覽器你不想阻止事件的默認(rèn)行為。

7.3 按鍵修飾符

<!-- 只有在 `key` 是 `Enter` 時(shí)調(diào)用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

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

<input v-on:keyup.page-down="onPageDown">

在上述示例中,處理函數(shù)只會(huì)在 $event.key 等于 PageDown 時(shí)被調(diào)用。

使用 keyCode 特性也是允許的:

<input v-on:keyup.13="submit">

為了在必要的情況下支持舊瀏覽器,Vue 提供了絕大多數(shù)常用的按鍵碼的別名:

  • .enter
  • .tab
  • .delete (捕獲“刪除”和“退格”鍵)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

有一些按鍵 (.esc 以及所有的方向鍵) 在 IE9 中有不同的 key 值, 如果你想支持 IE9,這些內(nèi)置的別名應(yīng)該是首選。

你還可以通過(guò)全局 config.keyCodes 對(duì)象自定義按鍵修飾符別名

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

系統(tǒng)修飾鍵
2.1.0 新增
可以用如下修飾符來(lái)實(shí)現(xiàn)僅在按下相應(yīng)按鍵時(shí)才觸發(fā)鼠標(biāo)或鍵盤事件的監(jiān)聽(tīng)器。

  • .ctrl
  • .alt
  • .shift
  • .meta

注意:在 Mac 系統(tǒng)鍵盤上,meta 對(duì)應(yīng) command 鍵 (?)。在 Windows 系統(tǒng)鍵盤 meta 對(duì)應(yīng) Windows 徽標(biāo)鍵 (?)。在 Sun 操作系統(tǒng)鍵盤上,meta 對(duì)應(yīng)實(shí)心寶石鍵 (◆)。在其他特定鍵盤上,尤其在 MIT 和 Lisp 機(jī)器的鍵盤、以及其后繼產(chǎn)品,比如 Knight 鍵盤、space-cadet 鍵盤,meta 被標(biāo)記為“META”。在 Symbolics 鍵盤上,meta 被標(biāo)記為“META”或者“Meta”。

例如:

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

請(qǐng)注意修飾鍵與常規(guī)按鍵不同,在和 keyup 事件一起用時(shí),事件觸發(fā)時(shí)修飾鍵必須處于按下?tīng)顟B(tài)。換句話說(shuō),只有在按住 ctrl 的情況下釋放其它按鍵,才能觸發(fā) keyup.ctrl。而單單釋放 ctrl 也不會(huì)觸發(fā)事件。如果你想要這樣的行為,請(qǐng)為 ctrl 換用 keyCodekeyup.17。

.exact 修飾符

2.5.0 新增

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

<!-- 沒(méi)有任何系統(tǒng)修飾符被按下的時(shí)候才觸發(fā) -->
<button @click.exact="onClick">A</button>

鼠標(biāo)按鈕修飾符

2.2.0 新增

  • .left
  • .right
  • .middle

這些修飾符會(huì)限制處理函數(shù)僅響應(yīng)特定的鼠標(biāo)按鈕。

8. 組件

8.1

<table>
    <tbody>
        <tr is=“row”></tr>
        <tr is=“row”></tr>
        <tr is=“row”></tr>
    </tbody>
</table>
vue.components('row',{
    template:'<tr><td>this os a row</td></tr>'
})

因?yàn)閔5有規(guī)定<tbody>內(nèi)只能寫<tr>,所以這里不能直接引用組件<row>,要通過(guò)以上方式引用,<ul>,<select>同理,建議用is=“”寫法

8.2 組件參數(shù)校驗(yàn)與非props特性

props:{
    content:{
        type: [String,Number],
        required:true  // 調(diào)用本組件的必傳的屬性
        default: 123   // 默認(rèn)值
        validator: function(value) {
            return value.length > 5   // 傳入的內(nèi)容長(zhǎng)度必須大于5
        }
    }
}

非props特性,即父組件傳遞給子組件的參數(shù)并沒(méi)有在子組件props中聲明,此時(shí)該傳遞會(huì)出現(xiàn)該子組件最外層dom標(biāo)簽中,(如果是props特性,則dom中不顯示 )如下:

<div content="hell">hello</div>

8.3 將原生事件綁定到組件

你可能有很多次想要在一個(gè)組件的根元素上直接監(jiān)聽(tīng)一個(gè)原生事件。這時(shí),你可以使用 v-on.native 修飾符:

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

在有的時(shí)候這是很有用的,不過(guò)在你嘗試監(jiān)聽(tīng)一個(gè)類似 <input> 的非常特定的元素時(shí),這并不是個(gè)好主意。比如上述 <base-input> 組件可能做了如下重構(gòu),所以根元素實(shí)際上是一個(gè) <label> 元素:

<label>
  {{ label }}
  <input
    v-bind="$attrs"
    v-bind:value="value"
    v-on:input="$emit('input', $event.target.value)"
  >
</label>

這時(shí),父級(jí)的 .native 監(jiān)聽(tīng)器將靜默失敗。它不會(huì)產(chǎn)生任何報(bào)錯(cuò),但是 onFocus 處理函數(shù)不會(huì)如你預(yù)期地被調(diào)用。
為了解決這個(gè)問(wèn)題,Vue 提供了一個(gè) $listeners 屬性,它是一個(gè)對(duì)象,里面包含了作用在這個(gè)組件上的所有監(jiān)聽(tīng)器。例如:

{
  focus: function (event) { /* ... */ }
  input: function (value) { /* ... */ },
}

有了這個(gè) $listeners 屬性,你就可以配合 v-on="$listeners" 將所有的事件監(jiān)聽(tīng)器指向這個(gè)組件的某個(gè)特定的子元素。對(duì)于類似 <input> 的你希望它也可以配合 v-model 工作的組件來(lái)說(shuō),為這些監(jiān)聽(tīng)器創(chuàng)建一個(gè)類似下述 inputListeners 的計(jì)算屬性通常是非常有用的:

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      // `Object.assign` 將所有的對(duì)象合并為一個(gè)新對(duì)象
      return Object.assign({},
        // 我們從父級(jí)添加所有的監(jiān)聽(tīng)器
        this.$listeners,
        // 然后我們添加自定義監(jiān)聽(tīng)器,
        // 或覆寫一些監(jiān)聽(tīng)器的行為
        {
          // 這里確保組件配合 `v-model` 的工作
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on="inputListeners"
      >
    </label>
  `
})

現(xiàn)在 <base-input> 組件是一個(gè)完全透明的包裹器了,也就是說(shuō)它可以完全像一個(gè)普通的 <input> 元素一樣使用了:所有跟它相同的特性和監(jiān)聽(tīng)器的都可以工作。

8.4 非父子組件間傳值(bus/總線/觀察者模式/發(fā)布訂閱模式)

<div id="root">
    <child content="Dell"></child>
    <child content="Lee"></child>
</div>

<script type="text/javascript">
    Vue.protopyte.bus = new Vue()
    Vue.component('child', {
        props: {
            content:String
        },
        template: '<div @click="childClick">{{content}}</div>',
        methods:{
            childClick: function() {
                this.bus.$emit('change',this.content)
            }
        },
        mounted: function() {  
            var self = this;
            this.bus.$on('change',function(msg) { // 監(jiān)聽(tīng)bus事件

            })
        }

    })
</script>

8.5 在vue中使用插槽(slot)

// 父:
<child>
    <p>內(nèi)容</p>
</child>

// 子:
<div>
    <slot>默認(rèn)內(nèi)容</slot>
</div>


// 父:
<child>
    <div class=“header” slot=“header”></div>
    <div class=“header” slot=“header”></div>
</child>

// 子:
<div>
    <slot name=“header”></slot>
    <div class=“content”>content</div>
    <slot name=“footer”></slot>
</div>

// vue中的作用域插槽
<child>
    <template slot-scope=“props”>  /*template必須要加上,props為接收的子組件數(shù)據(jù),名字可自定義*/
        <li>{{props.item}}</li>
    </template>
</child>

// 子組件
data: function(){
    return {
        list:[1,2,3,4]
    }
}
<div>
    <ul>
        <slot v-for=“item of list” :item=item></slot>
    </ul>
</div>

8.6 動(dòng)態(tài)組件 & 異步組件

我們之前曾經(jīng)在一個(gè)多標(biāo)簽的界面中使用 is 特性來(lái)切換不同的組件:

<component v-bind:is="currentTabComponent"></component>

當(dāng)在這些組件之間切換的時(shí)候,你有時(shí)會(huì)想保持這些組件的狀態(tài),以避免反復(fù)重渲染導(dǎo)致的性能問(wèn)題。例如我們來(lái)展開(kāi)說(shuō)一說(shuō)這個(gè)多標(biāo)簽界面:

Posts Archive

  • Cat Ipsum
  • Hipster Ipsum
  • Cupcake Ipsum

Click on a blog title to the left to view it.

你會(huì)注意到,如果你選擇了一篇文章,切換到 Archive 標(biāo)簽,然后再切換回 Posts,是不會(huì)繼續(xù)展示你之前選擇的文章的。這是因?yàn)槟忝看吻袚Q新標(biāo)簽的時(shí)候,Vue 都創(chuàng)建了一個(gè)新的 currentTabComponent 實(shí)例。

重新創(chuàng)建動(dòng)態(tài)組件的行為通常是非常有用的,但是在這個(gè)案例中,我們更希望那些標(biāo)簽的組件實(shí)例能夠被在它們第一次被創(chuàng)建的時(shí)候緩存下來(lái)。為了解決這個(gè)問(wèn)題,我們可以用一個(gè) <keep-alive> 元素將其動(dòng)態(tài)組件包裹起來(lái)。

<!-- 失活的組件將會(huì)被緩存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

來(lái)看看修改后的結(jié)果:

Posts Archive

  • Cat Ipsum
  • Hipster Ipsum
  • Cupcake Ipsum

Click on a blog title to the left to view it.

現(xiàn)在這個(gè) Posts 標(biāo)簽保持了它的狀態(tài) (被選中的文章) 甚至當(dāng)它未被渲染時(shí)也是如此。你可以在這個(gè) fiddle 查閱到完整的代碼。
注意這個(gè) <keep-alive> 要求被切換到的組件都有自己的名字,不論是通過(guò)組件的 name 選項(xiàng)還是局部/全局注冊(cè)。
你可以在 API 參考文檔 查閱更多關(guān)于 <keep-alive> 的細(xì)節(jié)。
加上exclude表示哪個(gè)組件不會(huì)被緩存

異步組件

在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時(shí)候才從服務(wù)器加載一個(gè)模塊。為了簡(jiǎn)化,Vue 允許你以一個(gè)工廠函數(shù)的方式定義你的組件,這個(gè)工廠函數(shù)會(huì)異步解析你的組件定義。Vue 只有在這個(gè)組件需要被渲染的時(shí)候才會(huì)觸發(fā)該工廠函數(shù),且會(huì)把結(jié)果緩存起來(lái)供未來(lái)重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回調(diào)傳遞組件定義
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如你所見(jiàn),這個(gè)工廠函數(shù)會(huì)收到一個(gè) resolve 回調(diào),這個(gè)回調(diào)函數(shù)會(huì)在你從服務(wù)器得到組件定義的時(shí)候被調(diào)用。你也可以調(diào)用 reject(reason) 來(lái)表示加載失敗。這里的 setTimeout 是為了演示用的,如何獲取組件取決于你自己。一個(gè)推薦的做法是將異步組件和 webpack 的 code-splitting 功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
  // 這個(gè)特殊的 `require` 語(yǔ)法將會(huì)告訴 webpack
  // 自動(dòng)將你的構(gòu)建代碼切割成多個(gè)包,這些包
  // 會(huì)通過(guò) Ajax 請(qǐng)求加載
  require(['./my-async-component'], resolve)
})

你也可以在工廠函數(shù)中返回一個(gè) Promise,所以把 webpack 2 和 ES2015 語(yǔ)法加在一起,我們可以寫成這樣:

Vue.component(
  'async-webpack-example',
  // 這個(gè) `import` 函數(shù)會(huì)返回一個(gè) `Promise` 對(duì)象。
  () => import('./my-async-component')
)

當(dāng)使用局部注冊(cè)的時(shí)候,你也可以直接提供一個(gè)返回 Promise 的函數(shù):

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

如果你是一個(gè) Browserify 用戶同時(shí)喜歡使用異步組件,很不幸這個(gè)工具的作者明確表示異步加載“并不會(huì)被 Browserify 支持”,至少官方不會(huì)。Browserify 社區(qū)已經(jīng)找到了一些變通方案,這些方案可能會(huì)對(duì)已存在的復(fù)雜應(yīng)用有幫助。對(duì)于其它的場(chǎng)景,我們推薦直接使用 webpack,以擁有內(nèi)置的頭等異步支持。

處理加載狀態(tài)

2.3.0+ 新增

這里的異步組件工廠函數(shù)也可以返回一個(gè)如下格式的對(duì)象:

const AsyncComponent = () => ({
  // 需要加載的組件 (應(yīng)該是一個(gè) `Promise` 對(duì)象)
  component: import('./MyComponent.vue'),
  // 異步組件加載時(shí)使用的組件
  loading: LoadingComponent,
  // 加載失敗時(shí)使用的組件
  error: ErrorComponent,
  // 展示加載時(shí)組件的延時(shí)時(shí)間。默認(rèn)值是 200 (毫秒)
  delay: 200,
  // 如果提供了超時(shí)時(shí)間且組件加載也超時(shí)了,
  // 則使用加載失敗時(shí)使用的組件。默認(rèn)值是:`Infinity`
  timeout: 3000
})

注意如果你希望在 Vue Router 的路由組件中使用上述語(yǔ)法的話,你必須使用 Vue Router 2.4.0+ 版本。

9. 動(dòng)畫

image
image

transition標(biāo)簽中不寫name屬性時(shí)默認(rèn)類名前綴為v,否則為name定義的名字


image

9.2. 幀動(dòng)畫

image

自定義類名

image

通過(guò)自定義類名方式可使用animate.css庫(kù),如果想要使頁(yè)面進(jìn)入時(shí)也具有動(dòng)畫,需加入如下紅框中的自定義類名

image

既有keyframe動(dòng)畫,又有transition動(dòng)畫,當(dāng)兩者動(dòng)畫時(shí)長(zhǎng)不同時(shí),通過(guò)設(shè)置type來(lái)規(guī)定用誰(shuí)的動(dòng)畫時(shí)長(zhǎng),或自己設(shè)置。:duration=“1000”
也可以分別給入場(chǎng),出場(chǎng)動(dòng)畫設(shè)置時(shí)長(zhǎng)
:duration=“{enter:5000,leave:10000}”

9.3 vue引入velocity.js

入場(chǎng)動(dòng)畫
第一個(gè)是事件觸發(fā)前
第二個(gè)是運(yùn)行動(dòng)畫效果時(shí)
最后是動(dòng)畫完成后
動(dòng)畫完成后要執(zhí)行done()函數(shù),一定要調(diào)用

image
image
image

出場(chǎng)動(dòng)畫

image

多個(gè)元素時(shí),同之前的組件復(fù)用,要想讓其顯示,需要加key

image

先顯示,再隱藏

image

先隱藏,在顯示,mode = “out-in”

動(dòng)態(tài)組件除了用以上多個(gè)元素的方式還可用以下方式

image

列表過(guò)渡

image

transition-group相當(dāng)于如下

9.4 動(dòng)畫封裝

image
image
image
image

以下為用js,不用css的情況

image

9.5 引入swiper插件 vue-awesome-swiper

如果很多地方都需要用,就全局引入

因?yàn)閟tyle設(shè)置了scoped,所以在這里修改swiper內(nèi)的樣式是無(wú)效的,這時(shí)需要按以下設(shè)置來(lái)突破scoped

.wrapper >>> .swiper-pagination-bullet-active
    background: #fff

窗口改變時(shí)swiper窗口重新計(jì)算

image

在Google 應(yīng)用商店下載vue.js devtools插件工具

當(dāng)圖標(biāo)超過(guò)8個(gè)時(shí)可以輪播,用計(jì)算屬性處理數(shù)據(jù)

computed: {
    pages () {
      const pages = []
      this.list.forEach((item, index) => {
        const page = Math.floor(index / 8)
        if (!pages[page]) {
          pages[page] = []
        }
        pages[page].push(item)
      })
      return pages
    }
  }

10. 常用知識(shí)點(diǎn)

10.1. 路由跳轉(zhuǎn)后頁(yè)面滾動(dòng)位置

image

10.2. 如果需要用ip地址訪問(wèn),需要在pack.json文件的npm run dev中加上如下:

image

10.3. vue在atom中配置emmet

https://github.com/emmetio/emmet-atom/issues/364
點(diǎn)擊文件 - 用戶鍵盤映射打開(kāi)配置文件
在配置文件的最后添加

'atom-text-editor[data-grammar~="vue"]:not([mini])':
    'tab':'emmet:expand-abbreviation-with-tab'

注意: 如果配置文件中已經(jīng)有'atom-text-editor[data-grammar~="vue"]:not([mini])':的其他配置, 那么要在其他配置的下面直接添加'tab': 'emmet:expand-abbreviation-with-tab', 而不能直接添加上面的兩行, 不然會(huì)報(bào)錯(cuò)
重啟編輯器
這樣就可以愉快的玩耍了...

10.4 vue 使用clipboard實(shí)現(xiàn)復(fù)制功能

https://blog.csdn.net/guxuehua/article/details/79169190

10.5. vue星星評(píng)論插件

https://github.com/shengxinjing/vue-tiny-rate
原理:將一行有顏色的星星定位覆蓋到無(wú)顏色的星星上,通過(guò)改變上層星星的width值來(lái)達(dá)到效果

10.6. promise封裝jsonp

// 引入jsonp插件
import originJsonp from 'jsonp'

export default function jsonp(url, data, option) {
  url += (url.indexOf('?') < 0 ? '?' : '&') + param(data) // 如果沒(méi)有問(wèn)號(hào)加問(wèn)號(hào),否則加&
  return new Promise((resolve, reject) => {
    originJsonp(url, option, (err, data) => {
      if (!err) {
        resolve(data)
      } else {
        reject(err)
      }
    })
  })
}

export function param(data) {
  let url = ''
  for (var k in data) {
    let value = data[k] !== undefined ? data[k] : ''
    url += `&${k}=${encodeURIComponent(value)}` // encodeURIComponent 把字符串作為url組件進(jìn)行編碼
  }
  return url ? url.substring(1) : '' // 有data時(shí)刪掉第一個(gè)&
}

10.7. Object.assign

// commonParams是一個(gè)對(duì)象
const data = Object.assign({}, commonParams, {// Object.assign 合并javascript對(duì)象
    platform: 'h5', // h5平臺(tái)
    uin: 0, // qq號(hào),默認(rèn)0
    needNewCode: 1
})

10.8 代理

在build目錄下的webpack.dev.conf.js文件中,加入如下代碼

const axios = require('axios')

const express = require('express')
const app = express()
var apiRoutes = express.Router()
app.use('/api', apiRoutes)

在devServer中加入
before(app) {
  app.get('/api/getDiscList', function (req, res) {
    var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
    axios.get(url, {
      headers: {
        referer: 'https://c.y.qq.com/',
        host: 'c.y.qq.com'
      },
      params: req.query //將參數(shù)返回給后端
    }).then((response) => {
      res.json(response.data)
    }).catch((e) => {
      console.log(e)
    })
  })
}

10.9 vue-lazyload插件

https://github.com/hilongjw/vue-lazyload

// 在main.js中引入
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad, {
  loading: require('common/image/default.png')
})
// 使用方法,將需要的地方的 :src改為v-lazy即可
<img v-lazy="img.src" >

10.10 常用樣式插件

import './assets/styles/reset.css'  // 重置樣式表
import './assets/styles/border.css'  // 移動(dòng)端1px像素問(wèn)題
import FastClick from 'fastclick'  //移動(dòng)端點(diǎn)擊300ms延遲問(wèn)題
FastClick.attach(document.body);

10.11 建分支

在碼云上建index-swiper分支,然后在本地

git pull
git checkout index-swiper 

// 合并分支
git checkout master 
git merge origin/index-swiper
git push 

10.12 圖片寬高自適應(yīng)

overflow:hidden
width:100%
height:0
padding-bottom: 31.25%
?著作權(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),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 基礎(chǔ)知識(shí): vue的生命周期: beforeCreate/created、 beforeMount/mounted...
    Jackson_yee_閱讀 407評(píng)論 0 0
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,180評(píng)論 0 29
  • vue概述 在官方文檔中,有一句話對(duì)Vue的定位說(shuō)的很明確:Vue.js 的核心是一個(gè)允許采用簡(jiǎn)潔的模板語(yǔ)法來(lái)聲明...
    li4065閱讀 7,624評(píng)論 0 25
  • 主要還是自己看的,所有內(nèi)容來(lái)自官方文檔。 介紹 Vue.js 是什么 Vue (讀音 /vju?/,類似于 vie...
    Leonzai閱讀 3,540評(píng)論 0 25
  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,373評(píng)論 0 6

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