|網(wǎng)站SEO建站,讓你的對手遙望我們一直在努力

前端開發(fā)詳解vue組件三大核心概念

您現(xiàn)在正位于該位置:高至 > 網(wǎng)站開發(fā) > 前端開發(fā)詳解vue組件三大核心概念
前言:本文主要介紹屬性、事件和插槽這三個vue基礎(chǔ)概念、使用方法及其容易被忽略的一些重要細(xì)節(jié)。如果你閱讀別人寫的組件,可以從這三個部分展開,它們可以幫助你快速了解一個組件的所有功能。
本文主要介紹屬性、事件和插槽這三個vue基礎(chǔ)概念、使用方法及其容易被忽略的一些重要細(xì)節(jié)。如果你閱讀別人寫的組件,可以從這三個部分展開,它們可以幫助你快速了解一個組件的所有功能。
前端開發(fā)
本文的代碼請猛戳https://github.com/ljianshu/Blog,紙上得來終覺淺,大家動手多敲敲代碼!
一、屬性
1.自定義屬性props
prop 定義了這個組件有哪些可配置的屬性,組件的核心功能也都是它來確定的。寫通用組件時,props 最好用對象的寫法,這樣可以針對每個屬性設(shè)置類型、默認(rèn)值或自定義校驗(yàn)屬性的值,這點(diǎn)在組件開發(fā)中很重要,然而很多人卻忽視,直接使用 props 的數(shù)組用法,這樣的組件往往是不嚴(yán)謹(jǐn)?shù)摹?/div>
// 父組件
 <props name=
'屬性'
           :type=
'type'
           :
is
-visible=
"false"
           :on-change=
"handlePropChange"
           :list=[
22
,
33
,
44
]
           title=
"屬性Demo"
           
class
=
"test1"
           :
class
=
"['test2']"
           :style=
"{ marginTop: '20px' }"
 
//注意:style 的優(yōu)先級是要高于 style
           style=
"margin-top: 10px"
>
  </props>
// 子組件
  props: {
    name: 
String
,
    type: {
   
//從父級傳入的 type,它的值必須是指定的 'success', 'warning', 'danger'中的一個,如果傳入這三個以外的值,都會拋出一條警告
      validator: (value) => {
        
return
 [
'success'
'warning'
'danger'
].includes(value)
      }
    },
    onChange: {
    
//對于接收的數(shù)據(jù),可以是各種數(shù)據(jù)類型,同樣也可以傳遞一個函數(shù)
      type: 
Function
,
      
default
: () => { }
    },
    isVisible: {
      type: 
Boolean
,
      
default
false
    },
    list: {
      type: 
Array
,
      
// 對象或數(shù)組默認(rèn)值必須從一個工廠函數(shù)獲取
      
default
: () => []
    }
  }
從上面的例中,可以得出props 可以顯示定義一個或一個以上的數(shù)據(jù),對于接收的數(shù)據(jù),可以是各種數(shù)據(jù)類型,同樣也可以傳遞一個函數(shù)。
 
2.inheritAttrs
這是2.4.0 新增的一個API,默認(rèn)情況下父作用域的不被認(rèn)作 props 的特性綁定將會“回退”且作為普通的 HTML 特性應(yīng)用在子組件的根元素上??赏ㄟ^設(shè)置 inheritAttrs 為 false,這些默認(rèn)行為將會被去掉。注意:這個選項不影響 class 和 style 綁定。 上個例中,title屬性沒有在子組件中props中聲明,就會默認(rèn)掛在子組件的根元素上,如下圖所示:
 
3. data與props區(qū)別
相同點(diǎn)
兩者選項里都可以存放各種類型的數(shù)據(jù),當(dāng)行為操作改變時,所有行為操作所用到和模板所渲染的數(shù)據(jù)同時都會發(fā)生同步變化。
 
不同點(diǎn)
data 被稱之為動態(tài)數(shù)據(jù),在各自實(shí)例中,在任何情況下,我們都可以隨意改變它的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu),不會被任何環(huán)境所影響。
 
props 被稱之為靜態(tài)數(shù)據(jù),在各自實(shí)例中,一旦在初始化被定義好類型時,基于 Vue 是單向數(shù)據(jù)流,在數(shù)據(jù)傳遞時始終不能改變它的數(shù)據(jù)類型,而且不允許在子組件中直接操作 傳遞過來的props數(shù)據(jù),而是需要通過別的手段,改變傳遞源中的數(shù)據(jù)。至于如何改變,我們接下去詳細(xì)介紹:
 
4.單向數(shù)據(jù)流
這個概念出現(xiàn)在組件通信。props的數(shù)據(jù)都是通過父組件或者更高層級的組件數(shù)據(jù)或者字面量的方式進(jìn)行傳遞的,不允許直接操作改變各自實(shí)例中的props數(shù)據(jù),而是需要通過別的手段,改變傳遞源中的數(shù)據(jù)。那如果有時候我們想修改傳遞過來的prop,有哪些辦法呢?
 
方法1:過渡到 data 選項中
在子組件的 data 中拷貝一份 prop,data 是可以修改的
 
export
 
default
 {
  props: {
    type: 
String
  },
  data () {
    
return
 {
      currentType: 
this
.type
    }
  }
}
在 data 選項里通過 currentType接收 props中type數(shù)據(jù),相當(dāng)于對 currentType= type進(jìn)行一個賦值操作,不僅拿到了 currentType的數(shù)據(jù),而且也可以改變 currentType數(shù)據(jù)。
 
方法2:利用計算屬性
export
 
default
 {
  props: {
    type: 
String
  },
  computed: {
    normalizedType: 
function
 () {
      
return
 
this
.type.toUpperCase();
    }
  }
}
以上兩種方法雖可以在子組件間接修改props的值,但如果子組件想修改數(shù)據(jù)并且同步更新到父組件,卻無濟(jì)于事。在一些情況下,我們可能會需要對一個 prop 進(jìn)行『雙向綁定』,此時就推薦以下這兩種方法:
 
方法3:使用.sync
// 父組件
<template>
  <div 
class
=
"hello"
>
    
<div>
      
<p>
父組件msg:{{ msg }}</p>
      
<p>
父組件數(shù)組:{{ arr }}</p>
    </div>
    <button 
@click
=
"show = true"
>打開model框</button>
    <br />
    <demo :show.sync=
"show"
 :msg.sync=
"msg"
 :arr=
"arr"
></demo>
  </div>
</
template
>
 
<script>
import
 
Demo
 
from
 
"./demo.vue"
;
export
 
default
 {
  name: 
"Hello"
,
  components: {
    
Demo
  },
  data() {
    
return
 {
      show: 
false
,
      msg: 
"模擬一個model框"
,
      arr: [
1
2
3
]
    };
  }
};
</script>
// 子組件
<template>
  <div v-
if
=
"show"
 
class
=
"border"
>
    
<div>
子組件msg:{{ msg }}</div>
    
<div>
子組件數(shù)組:{{ arr }}</div>
    <button 
@click
=
"closeModel"
>關(guān)閉model框</button>
    <button 
@click
=
"$emit('update:msg', '浪里行舟')"
>
      改變文字
    </button>
    <button 
@click
=
"arr.push('前端工匠')"
>改變數(shù)組</button> 
  </div>
</
template
>
<script>
export
 
default
 {
  props: {
    msg: {
      type: 
String
    },
    show: {
      type: 
Boolean
    },
    arr: {
      type: 
Array
 
//在子組件中改變傳遞過來數(shù)組將會影響到父組件的狀態(tài)
    }
  },
  methods: {
    closeModel() {
      
this
.$emit(
"update:show"
false
);
    }
  }
};
 
 
父組件向子組件 props 里傳遞了 msg 和 show 兩個值,都用了.sync 修飾符,進(jìn)行雙向綁定。 不過.sync 雖好,但也有限制,比如:
 
1)不能和表達(dá)式一起使用(如 v-bind:title.sync="doc.title + '!'"是無效的); 2)不能用在字面量對象上(如 v-bind.sync="{ title: doc.title }"是無法正常工作的)。
 
方法4:將父組件中的數(shù)據(jù)包裝成對象傳遞給子組件
這是因?yàn)樵?JavaScript 中對象和數(shù)組是通過引用傳入的,所以對于一個數(shù)組或?qū)ο箢愋偷?prop 來說,在子組件中改變這個對象或數(shù)組本身將會影響到父組件的狀態(tài)。比如上例中在子組件中修改父組件傳遞過來的數(shù)組arr,從而改變父組件的狀態(tài)。
 
5.向子組件中傳遞數(shù)據(jù)時加和不加 v-bind?
對于字面量語法和動態(tài)語法,初學(xué)者可能在父組件模板中向子組件中傳遞數(shù)據(jù)時到底加和不加 v-bind 會感覺迷惑。
 
v-bind:msg = 'msg'
這是通過 v-bind 進(jìn)行傳遞數(shù)據(jù)并且傳遞的數(shù)據(jù)并不是一個字面量,雙引號里的解析的是一個表達(dá)式,同樣也可以是實(shí)例上定義的數(shù)據(jù)和方法(其實(shí)就是引用一個變量)。
 
msg='浪里行舟'
這種在沒有 v-bind 的模式下只能傳遞一個字面量,這個字面量只限于 String 類量,字符串類型。那如果想通過字面量進(jìn)行數(shù)據(jù)傳遞時,如果想傳遞非String類型,必須props名前要加上v-bind,內(nèi)部通過實(shí)例尋找,如果實(shí)例方?jīng)]有此屬性和方法,則默認(rèn)為對應(yīng)的數(shù)據(jù)類型。
 
:msg=
'11111'
 
//Number 
:msg=
'true'
 
//Bootlean 
:msg=
'()=>{console.log(1)}'
 
//Function
:msg=
'{a:1}'
 
//Object
二、事件
1.事件驅(qū)動與數(shù)據(jù)驅(qū)動
用原生JavaScript事件驅(qū)動通常是這樣的流程:
 
先通過特定的選擇器查找到需要操作的節(jié)點(diǎn) -> 給節(jié)點(diǎn)添加相應(yīng)的事件監(jiān)聽
然后用戶執(zhí)行某事件(點(diǎn)擊,輸入,后退等等) -> 調(diào)用 JavaScript 來修改節(jié)點(diǎn)
這種模式對業(yè)務(wù)來說是沒有什么問題,但是從開發(fā)成本和效率來說會比較不理想,特別是在業(yè)務(wù)系統(tǒng)越來越龐大的時候。另一方面,找節(jié)點(diǎn)和修改節(jié)點(diǎn)這件事,效率本身就很低,因此出現(xiàn)了數(shù)據(jù)驅(qū)動模式。
 
Vue的一個核心思想是數(shù)據(jù)驅(qū)動。所謂數(shù)據(jù)驅(qū)動,是指視圖是由數(shù)據(jù)驅(qū)動生成的,我們對視圖的修改,不會直接操作 DOM,而是通過修改數(shù)據(jù),其流程如下:
 
用戶執(zhí)行某個操作 -> 反饋到 VM 處理(可以導(dǎo)致 Model 變動) -> VM 層改變,通過綁定關(guān)系直接更新頁面對應(yīng)位置的數(shù)據(jù)
 
可以簡單地理解:數(shù)據(jù)驅(qū)動不是操作節(jié)點(diǎn)的,而是通過虛擬的抽象數(shù)據(jù)層來直接更新頁面。主要就是因?yàn)檫@一點(diǎn),數(shù)據(jù)驅(qū)動框架才得以有較快的運(yùn)行速度(因?yàn)椴恍枰フ垓v節(jié)點(diǎn)),并且可以應(yīng)用到大型項目。
 
2.修飾符事件
Vue事件分為普通事件和修飾符事件,這里我們主要介紹修飾符事件。
 
Vue 提供了大量的修飾符封裝了這些過濾和判斷,讓開發(fā)者少寫代碼,把時間都投入的業(yè)務(wù)、邏輯上,只需要通過一個修飾符去調(diào)用。我們先來思考這樣問題:怎樣給這個自定義組件 custom-component 綁定一個原生的 click 事件?
 
<custom-component>
組件內(nèi)容
</custom-component>
如果你的回答是 <custom-component@click="xxx">,那就錯了。這里的 @click 是自定義事件 click,并不是原生事件 click。綁定原生的 click 是這樣的:
 
<custom-component
 @
click
.
native
=
"xxx"
>
組件內(nèi)容
</custom-component>
實(shí)際開發(fā)過程中離不開事件修飾符,常見事件修飾符有以下這些:
 
表單修飾符
1).lazy
 
在默認(rèn)情況下, v-model 在每次 input 事件觸發(fā)后將輸入框的值與數(shù)據(jù)進(jìn)行同步 。你可以添加 lazy 修飾符,從而轉(zhuǎn)變?yōu)槭褂?change事件進(jìn)行同步。適用于輸入完所有內(nèi)容后,光標(biāo)離開才更新視圖的場景。
 
2).trim
 
如果要自動過濾用戶輸入的首尾空白字符,可以給 v-model 添加 trim 修飾符:
 
<input
 
v-model
.
trim
=
"msg"
>
這個修飾符可以過濾掉輸入完密碼不小心多敲了一下空格的場景。需要注意的是,它只能過濾首尾的空格!首尾,中間的是不會過濾的。
 
3).number
 
如果想自動將用戶的輸入值轉(zhuǎn)為數(shù)值類型,可以給 v-model 添加 number 修飾符:
 
<input
 
v-model
.
number
=
"value"
 
type
=
"text"
 
/>
 
從上面例子,可以得到如果你先輸入數(shù)字,那它就會限制你輸入的只能是數(shù)字。如果你先輸入字符串,那它就相當(dāng)于沒有加.number
 
事件修飾符
<!-- 阻止單擊事件繼續(xù)傳播 -->
<a
 
v-on:click
.
stop
=
"doThis"
></a>
 
<!-- 提交事件不再重載頁面 -->
<form
 
v-on:submit
.
prevent
=
"onSubmit"
></form>
 
<!-- 修飾符可以串聯(lián) -->
<a
 
v-on:click
.
stop
.
prevent
=
"doThat"
></a>
三、插槽
插槽分為普通插槽和作用域插槽,其實(shí)兩者很類似,只不過作用域插槽可以接受子組件傳遞過來的參數(shù)。
 
1.作用域插槽
我們不妨通過一個todolist的例子來了解作用域插槽。如果當(dāng)item選中后,文字變?yōu)辄S色(如下圖所示),該如何實(shí)現(xiàn)呢?其中難點(diǎn)就是子組件如何通過作用域插槽向父組件傳值?
 
 
// 父組件
<template>
  <div 
class
=
"toList"
>
    <input v-model=
"info"
 type=
"text"
 /> <button 
@click
=
"addItem"
>添加</button>
    
<ul>
      <
TodoItem
 v-
for
=
"(item, index) in listData"
 :key=
"index"
>
        <
template
 v-slot:item=
"itemProps"
// 這是個具名插槽
        
// 其中itemProps的值就是子組件傳遞過來的對象
          <span
            :style=
"{
              fontSize: '20px',
              color: itemProps.checked ? 'yellow' : 'blue'
            }"
            >{{ item }}</span
          >
        </
template
>
      </
TodoItem
>
    </ul>
  </div>
</
template
>
<script>
import
 
TodoItem
 
from
 
"./TodoItem"
;
export
 
default
 {
  components: {
    
TodoItem
  },
  data() {
    
return
 {
      info: 
""
,
      listData: []
    };
  },
  methods: {
    addItem() {
      
this
.listData.push(
this
.info);
      
this
.info = 
""
;
    }
  }
};
</script>
// 子組件
<template>
  
<div>
    <li 
class
=
"item"
>
      <input v-model=
"checked"
 type=
"checkbox"
 />
      <slot name=
"item"
 :
checked
=
"checked"
><
/slot> /
/ 將
checked
的值傳遞給父組件
    </li>
  </div>
</
template
>
<script>
export
 
default
 {
  data() {
    
return
 {
      
checked
false
    };
  }
};
</script>
值得注意:v-bind:style 的對象語法十分直觀——看著非常像 CSS,但其實(shí)是一個 JavaScript 對象。CSS 屬性名可以用駝峰式 (camelCase) 或短橫線分隔 (kebab-case,記得用引號括起來) 來命名。
 
2.v-slot新語法
在 2.6.0 中,我們?yōu)榫呙宀酆妥饔糜虿宀垡肓艘粋€新的統(tǒng)一的語法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 。 我們通過一個例子介紹下默認(rèn)插槽、具名插槽和作用域插槽的新語法:
 
// 父組件
<template>
  <div 
class
=
"helloSlot"
>
    
<h2>
2.6
 新語法</h2>
    <
SlotDemo
>
      
<p>
默認(rèn)插槽:
default
 slot</p>
      <
template
 v-slot:title>
        
<p>
具名插槽:title slot1</p>
        
<p>
具名插槽:title slot2</p>
      </
template
>
      <
template
 v-slot:item=
"props"
>
        
<p>
作用域插槽:item slot-scope {{ props }}</p>
      </
template
>
    </
SlotDemo
>
  </div>
</
template
>
<script>
import
 
Slot
 
from
 
"./slot"
;
export
 
default
 {
  components: {
    
SlotDemo
Slot
  }
};
</script>
// 子組件
<template>
  
<div>
    <slot />
    <slot name=
"title"
 />
    <slot name=
"item"
 :propData=
"propData"
 />
  </div>
</
template
>
<script>
export
 
default
 {
  data() {
    
return
 {
      propData: {
        value: 
"浪里行舟"
      }
    };
  }
};
</script>
 
 
參考文章
Vue開發(fā)實(shí)戰(zhàn)
Vue.js 組件精講
Vue.js 官方文檔
Vue 組件通信全揭秘
vue修飾符--可能是東半球最詳細(xì)的文檔
轉(zhuǎn)載請注明出處及附上該鏈接:http://ebqao.cn/web/378.html

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

上一篇:<<前端有哪些技術(shù)在未來的地位會更吃香 下一篇:新手站長網(wǎng)里面決定網(wǎng)站生死的幾個重要的因素>>