vue2.X心得

VUEJS學習網址:https://cn.vuejs.org/javascript

此文章是用來記錄本身的學習和實踐心得。css

關注點:父子組件之間的通訊

看圖說話:html

Pass Propsvue

  • 子組件自己與父組件是孤立的,經過子組件中顯示聲明的props屬性,接收父組件數據;
  • 父組件的數據更新時,子組件的prop會跟着更新;
  • 此數據流動是單向的(看着);

Emit Eventsjava

  • 子組件使用$.emit(fn)向外拋出本身的內部觸發的事件;
  • 父組件是否監聽?若是父組件須要監聽,使用v-on綁定監聽,觸發對應事件;

以上爲通用語,具體分析react

  • 子組件能夠接收一個字符串,在子組件內部能夠用{{label}}使用 
<v-input label="姓名"></v-input>
  • 子組件能夠接收動態參數
<input v-model="msg" />
<v-profile :message="msg"></v-profile>

子組件接收到數據以後想處理一下不當心改了怎麼辦?git

  • 給prop建立一個副本(建議深拷貝),處理副本,不動prop;

父組件的數據改變後,子組件的prop會自動更新,可是這個prop的副本不會啊?github

  • 使用watch監聽這個prop,改變時更新副本;

子組件的prop副本改變了想要通知父組件怎麼辦?web

  • 使用watch監聽這個副本,改變時向外拋出本身的內部觸發的事件;

(添加)父組件的prop改變,可是不想通知子組件怎麼辦?vue-router

  • 使用.once顯式指定單次綁定

。。。

其實以上???在2.3有了更好的方法,以前的就是看看。

.sync修飾符

***父組件***
<input v-model="msg" />
<v-profile :message.sync="msg"></v-profile>
***子組件***
$.emit('update:message',newValue)

(9-21)補充:註釋仍是建議使用data或compute屬性,而不是直接修改prop

子組件想要觸發父組件能夠emit(父組件須要監聽纔會觸發),父組件觸發子組件事件呢?

  • 經過在引用的子組件上使用ref屬性實現父組件調用子組件的方法以及屬性

可是$refs 只在組件渲染完成後才填充,而且它是非響應式的。它僅僅做爲一個直接訪問子組件的應急方案——應當避免在模版或計算屬性中使用 $refs 。

關注點:非父子組件之間的通訊

 使用空的vue實例做爲中央事件總線

var bus = new Vue();
// 觸發組件 A 中的事件
bus.$emit('id-selected', 1)


// 在組件 B 建立的鉤子中監聽事件
bus.$on('id-selected', function (id) {
  // ...
})

考慮vuex

(2018-07-28)注意到了$attrs和¥listeners,用於在多層嵌套中交互,見文檔

關注點:在組件中使用slot

首先,在父組件中給子組件標籤中間放置內容是無效的。而後slot出場。

白話版本:

匿名slot:
    slot標籤存在與子組件template中;
    子組件在父組件中使用的時候,子組件標籤中的結構會在編譯後替換子組件的slot標籤;
若是子組件中沒有slot,則父組件中子組件標籤中的內容會消失; 具名slot: 顧名思義,是具備name屬性的slot標籤;並有匿名組件的特性(以上); 子組件在父組件中使用的時候,子組件中的結構中會有某些標籤擁有slot屬性並賦值,這些會在編譯後替換子組件的相應slot標籤;

一句話解釋:主要的內容是寫在父組件中的子組件標籤中,編譯後插入子組件的相應位置

講真,說到這裏我本身都不明白要slot幹嗎。

官方講解入口

官方給了個佈局的例子:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
View Code
<app-layout>
  <h1 slot="header">這裏多是一個頁面標題</h1>
  <p>主要內容的一個段落。</p>
  <p>另外一個主要段落。</p>
  <p slot="footer">這裏有一些聯繫信息</p>
</app-layout>
View Code

可是好像也沒什麼好推薦的。(我的見解)

再想一想:

子組件的template中至少有一個slot標籤,slot標籤中的內容是default content。什麼場景能用到呢?我想到了剛剛寫的表格數據篩選,當時用的是v-if,v-else。若是改爲slot呢。。。想到slot屬性值須要動態傳餐,原來寫在子組件內部的過濾過程要搬出來放到父組件中執行,而後把執行好的數據塞給子組件的prop。。。

再理一次:

我在子組件的template中設置兩個slot

<slot name="Data">各類展示數據的結構都放這裏</slot>
<slot name="noData">沒有相關數據</slot>

父組件中設置

<input v-model="filterData" />
<button v-on:click="filterMethod">篩選</button>
<v-table :datas="datas">
    <div slot="Data">
    ...
  <div> <v-tabel>

關鍵就是slot屬性動態賦值的問題。。。走不通,腦洞大了按下不說了

做用域插槽

語法:

<template scope="props">
  ...
</template>

 ——————這個官網例子我是好半天才明白

<my-awesome-list :items="items">
  <!-- 做用域插槽也能夠是具名的 -->
  <template slot="item" scope="props">
    <li class="my-fancy-item">{{ props.text }}</li>
  </template>
</my-awesome-list>

以上的template中的props其實和子組件的props屬性是相同的,子組件傳遞了什麼prop,它就接收什麼,像是下邊的傳了個text

<ul>
  <slot name="item"
    v-for="item in items"
    :text="item.text">
    <!-- 這裏寫入備用內容 -->
  </slot>
</ul>

我看了很長很長時間,爲何要這麼拐個彎呢。。。

————一晚上事後—————

這樣內容更靈活:數據是相同的(父組件提供數據),子組件負責了循環(添加邏輯),父組件引用子組件時插入的做用域插槽的模板決定了(展現的形式)!這分工!!!點個贊!!!

我修改了一下本身的table而後頁面展現了個空白。以後發現問題出在子組件往外傳數據的時候變量名不能用"name"。修改掉。2017-07-14:使用index也不行。。。

2017-07-15:在實際使用的時候發現複用性不強。感受父子組件之間聲明式props傳遞數據的方式使加強複用性變得困難。

關注點:動態組件使用

  • 經過使用保留的 <component> 元素,動態地綁定到它的 is 特性,咱們讓多個組件可使用同一個掛載點,並動態切換:很適用於製做Tab類的效果
<component v-bind:is="currentView" :data1="data1" :data2="data2">
  <!-- 組件在 vm.currentview 變化時改變! -->
</component>
  • 在methods屬性中定義一個函數修改currentView便可。
  • 視狀況能夠配合 keep-alive 避免從新渲染
  • 在子組件上放置activated鉤子作切換時的工做:done() //放到鉤子最後,表示執行工做完畢,能夠切換組件,配合keep-alive使用,activated鉤子只執行一次
  • 子組件接收數據和以往相同,只是這一次都寫在了component中,只是如此的話,每一個子組件都須要有這些接口(prop)

暫時說到這裏,忽然得回頭看一下react,沒時間了,回頭會繼續。

以上的滿基礎的(我是新手),有什麼不對的求指出,感謝!!!

添加:

關注點:組件間的循環引用

使用全局註冊的時候沒有問題(框架自行解決)

若是是模塊引用(我都是這樣的),須要在第一次循環的子組件上聲明

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue')
}

本身模仿的示例

treeFolder

<template>
<ul>
<li v-for="folder in folders">
<span @click="toggle(folder)">folder.name:{{folder.name}}</span>
<tree-folder-content v-if="folder.children"
:children="folder.children"
v-show="folder.show"
/>
</li>
</ul>
</template>
<script>
import treeFolderContent from './treeFolderContent.vue';
export default{
name: "tree-folder",
data(){
return {
expand: false
}
},
components: {
'tree-folder-content': treeFolderContent
},
props: ['folders'],
methods:{
toggle: function(item) {
item.show = !item.show;
}
}
}
</script>

 treeFolderContent

<template>
<ul>
<li v-for="child in children">
<span @click="toggle(child)">child.name:{{child.name}}</span>
<TreeFolder v-if="child.children"
:folders="child.children"
v-show="child.show"
/>
</li>
</ul>
</template>
<script>
export default{
name: "tree-folder-content",
beforeCreate(){
this.$options.components.TreeFolder = require('./treeFolder.vue');
},
data(){
return {
expand: false
}
},
props: ['children'],
methods:{
toggle: function(item) {
item.show = !item.show;
}
}
}
</script>

引用方式

<template>
<div class="main">
<div class="content">
<tree-folder :folders="menu"></tree-folder>
</div>
</div>
</template>
<script>
import treeFolder from './../commen/treeFolder.vue'
export default{
name: "nav3",
data(){
return {
menu: [
{
name: 'a一級導航', show: true,
children: [
{name: 'a二級導航', show: false},
{name: 'a二級導航', show: false}
]
},
{
name: 'b一級導航', show: true,
children: [
{name: 'b二級導航', show: false},
{name: 'b二級導航', show: false},
{
name: 'b二級導航', show: false,
children: [
{
name: 'b三級導航', show: false,
children: [
{name: 'b四級導航', show: false,}
]
}
]
},
]
},
{
name: 'c一級導航', show: true,
children: [
{name: 'c二級導航', show: false},
{name: 'c二級導航', show: false},
{
name: 'c二級導航', show: false,
children: [
{name: 'c三級導航', show: false}
]
},
]
}
]
}
},
components: {
'tree-folder': treeFolder
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less" rel="stylesheet/less">
.content {
background: blue;
color: #fff;
}
</style>

 

小點tip:

  • 低開銷的靜態組件使用v-once(2017-07-15修改,以前誤寫成v-on):儘管在 Vue 中渲染 HTML 很快,不過當組件中包含大量靜態內容時,能夠考慮使用 v-once將渲染結果緩存起來;

 關注點:關於過濾器

vue1.x版本中有不少系統自帶的過濾器,在vue2.x版本中都沒有了。

  • 對於刪除掉的那些過濾器可使用Vue.filter()在全局註冊自定義相同功能。必須放在Vue實例化前面。
  • 或是使用filters在示例內部註冊
  • 或是使用Array的新語法filter和computed屬性先處理數據返回新的data

2017-07-15

關注點:組件生命週期

 

看圖說話:

    1. beforeCreated:聲明------建立實例,可是實例並未建立的階段,這時候關於Vue實例的屬性和方法等都尚未讀取到。這是Vuejs實例週期中的第一個階段,在DOM展現出來(mounted)還有一段時間,咱們能夠在這裏添加loading,增長用戶體驗。例如:document.body.appendChild(loading);
    2. created:實例已經建立好了,讀到了data(observe data)和自帶的事件(Init Event),此時在鉤子中運行console.log(this)查看輸出。這時候咱們能夠作一些異步請求,例如請求一些服務器上的數據等。
    3. 這個Vue實例有el屬性嗎?若是沒有,使用.$mounted("#app")使組件在mounted階段掛載到#app下;若是有,直接在mounted階段掛載到#app下;
    4. 這個Vue實例有template嗎?若是有,把template編譯成render函數(render函數構造虛擬DOM);若是沒有,將el的outerHTML(包括el自己)當作template編譯成render函數;
    5. beforeMounted:不知道這時候幹什麼好
    6. mounted:此時,使用vue生成的DOM結構將代替el,能夠操做新的#app的DOM結構了,此時,在beforeCreated階段添加的loading能夠消失了;(在這裏,我最開始寫的是document.body.removeChild(loading);然而並無什麼用,只能給loading加上類名從新選定刪除,如下是loading代碼。若是是我JS不精形成的問題,請指出!!!):::::::::::20180430:注意 mounted 不會承諾全部的子組件也都一塊兒被掛載。若是你但願等到整個視圖都渲染完畢,能夠用 vm.$nextTick 替換掉 mounted。OK,問題解決。
    7. DOM展示給用戶後,用戶操做(v-on)引起data change。可是這時候並非直接操做DOM,而是操做虛擬dom(我的理解:由vue-loader將vue組件文件中的代碼解析成了javascript,(render的過程)在用戶操做的時候,最早操做這些僞DOM(js操做),而後在re-render成真正的DOM。再此,也總結出vue的一大特色:data和dom並非直接通信,而是經過虛擬dom)。這裏又牽扯出了數據驅動。。。看圖。。。先看看,等等換成新的關注點吧(>.<)

    8. beforeUpdata:數據已更新,可是虛擬 DOM 從新渲染和打補丁以前觸發,此時還能夠對data進行操做,此時的data修改並不會觸發重渲染(完成你的自定義操做一塊兒渲染)。官網上有一句:該鉤子在服務器端渲染期間不被調用。沒有接觸服務器端渲染,不談。
    9. re-render
    10. updated:此時DOM已經更新了(mounted)

      當這個鉤子被調用時,組件 DOM 已經更新,因此你如今能夠執行依賴於 DOM 的操做。然而在大多數狀況下,你應該避免在此期間更改狀態。若是要相應狀態改變,一般最好使用計算屬性或 watcher 取而代之。(官網原文,我以爲記着就好)

      該鉤子在服務器端渲染期間不被調用。

    11. 若是調用了vm.$destroy()(將new Vue({})賦值給變量vm),會先觸發beforeDestroy鉤子,此時,仍是能夠操做實例;destroyed鉤子緊接着被調用。。。就將全部的watcher,components,listeners刪除(此時請再看一眼數據驅動原理圖)。以後我又console.log(vm),在控制檯上仍是可以訪問到這個實例Vue$3(怎麼命名的啊),換言之,這個實例只是回到了beforeCreated階段。已經渲染出來的DOM,若是依賴data和init event則會消失,不依賴的會留下。
//用Javascript代碼表示DOM節點的僞代碼
Let domNode = {
  tag: 'ul'
  attributes: { id: 'myId' }
  children: [
//這裏是 li
  ]
};
var loading = document.createElement("div");
loading.style.width = "1000px";
loading.style.height = "1000px";
loading.className = 'loading';
loading.style.backgroundColor = "#000";

數據驅動原理

關注點:表格展現示例

連接:

2017-07-17

關注點:動畫

會有 6 個(CSS)類名在 enter/leave 的過渡中切換

  1. v-enter: 定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。

  2. v-enter-active: 定義過渡的狀態。在元素整個過渡過程當中做用,在元素被插入時生效,在 transition/animation 完成以後移除。 這個類能夠被用來定義過渡的過程時間,延遲和曲線函數。

  3. v-enter-to: 2.1.8版及以上 定義進入過渡的結束狀態。在元素被插入一幀後生效(於此同時 v-enter 被刪除),在 transition/animation 完成以後移除。

  4. v-leave: 定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。

  5. v-leave-active: 定義過渡的狀態。在元素整個過渡過程當中做用,在離開過渡被觸發後當即生效,在 transition/animation 完成以後移除。 這個類能夠被用來定義過渡的過程時間,延遲和曲線函數。

  6. v-leave-to: 2.1.8版及以上 定義離開過渡的結束狀態。在離開過渡被觸發一幀後生效(於此同時 v-leave 被刪除),在 transition/animation 完成以後移除。

看概念並不難,直接說我跳過的坑:

css過渡

  • 若是設置了v-enter-to,過渡的是v-enter到v-enter-to,若是沒有,就是v-enter到你加入動畫以前的最初樣式,同理v-leave-to
  • 自定類名的時候可使用name屬性重置v前綴 

css動畫 顧名思義,是動畫 animation 。

搭配animate.css一塊兒使用。能夠經過如下特性來自定義過渡類名:他們的優先級高於普通的類名

  • enter-class
  • enter-active-class
  • enter-to-class (>= 2.1.8 only)
  • leave-class
  • leave-active-class
  • leave-to-class (>= 2.1.8 only)

關注點:方法事件處理器 methods

  • 在內聯方法中傳入特殊變量$event,能夠在methods中定義的該方法中訪問原生事件對象。
  • 在事件處理程序中調用 event.preventDefault() 或 event.stopPropagation() 是很是常見的需求。儘管咱們能夠在 methods 中輕鬆實現這點,但更好的方式是:methods 只有純粹的數據邏輯,而不是去處理 DOM 事件細節。(原文)
<button v-on:click="warn(' ...', $event)">
  Submit
</button>
......
methods: {
  warn: function (message, event) {
    // 如今咱們能夠訪問原生事件對象
    if (event) event.preventDefault()
    alert(message)
  }
}

關注點:事件修飾符

<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 阻止默認事件 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 點擊事件將只會觸發一次 -->
<a v-on:click.once="doThis"></a>

<!-- 只有在 keyCode 是 13 時調用 vm.submit() -->
<input v-on:keyup.13="submit">
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 縮寫語法 -->
<input @keyup.enter="submit">

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

自定義鍵值修飾符
Vue.config.keyCodes.f1 = 112

鼠標或鍵盤事件監聽

.ctrl
.alt
.shift
.meta

關注點:命名視圖

https://jsfiddle.net/posva/6du90epg/

關注點:v-once 與 keep-alive

今天把本身寫的心得又讀了一遍,對v-once 和keep-alive有點迷惑

v-once只渲染元素和組件一次。隨後的從新渲染,元素/組件及其全部的子節點將被視爲靜態內容並跳過。這能夠用於優化更新性能。

keep-alive包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。

 

今天11月30日,由於一些緣由我有2個月沒有注意「vuejs」,就這樣它悄悄地改變了。。。

紙上得來終覺淺,但願有機會去實踐。

 

實踐來了。

2018.1.15

工做告一個段落了,使用公司的接口將新的webApp項目改爲了vuejs項目。不是每一個頁面都從新寫了,時間也是不容許的吧。

實現:vue-router,vuex,vue-resourse,selected,下拉加載,輸入框和select等。

地址:*********************老大說放公司代碼屬於侵權。。。

不會再新增關於vue的新隨筆,就這一篇,不斷的補充,感受也挺好。(我又加了一個關於框架的。。。)

關注點:watch

watch用來監控某個變化的屬性,而後執行方法。在我以往的使用中,只有該監控的屬性發生變化時纔會觸發方法。

  • 若果想要初始時就執行這個方法,須要傳入新的屬性immediate,而以前的方法寫到handler中,語法格式如watch: { XXXX: { handler(arg1,arg2,...) { ...},immediate: Bealoon} }。
  • 若想監控到對象某個屬性的變化(Vue 不能檢測到對象屬性的添加或刪除),以往我是直接給整個對象從新賦值,可是實際上能夠經過watcher的deep屬性作深層監控,語法同上一條,deep取值爲Bealoon。
  • watch請儘可能寫在使用的組件中,監聽對象也是組件內有效的,而不是在全局聲明一個watch---這樣你可能在不想觸發的時候觸發它。

 2018-08-01  在項目中使用vue有半年了,這半年來項目不斷,也算是用vue‘摸爬滾打’了,可是總以爲淺。想的用的都很表面,只是‘能跑通’罷了。挫敗。

相關文章
相關標籤/搜索