好一段時(shí)間沒寫文章了喷楣。嗯趟大,之前欠的nodemcu的文章,我會(huì)找時(shí)間補(bǔ)上的铣焊。剛好項(xiàng)目組推新的固件逊朽,加入幾個(gè)新的模塊。放心曲伊,我一定會(huì)更新那個(gè)系列的文章的叽讳,只有有時(shí)間相信未來一段時(shí)間都沒有的話。??
這回帶來的是有關(guān)寫Vue組件(.vue)的文章坟募。主要會(huì)涉及的內(nèi)容包括props岛蚤,data, methods等一系列概念懈糯。力爭(zhēng)用最簡(jiǎn)單的語(yǔ)言讓像我一樣的萌新可以快速上手寫出Vue組件來涤妒。跟著本來走一遍可以得到下面的效果。GitHub
創(chuàng)建一個(gè)工程
直接使用vue-cli創(chuàng)建一個(gè)webpack工程赚哗。雖然官方文檔里面建議新手不要使用構(gòu)建工具她紫。不過,個(gè)人覺得用這個(gè)創(chuàng)建工程學(xué)習(xí)vue也蠻爽的蜂奸。工具將很多工具打包到工程里面來犁苏,提供了一個(gè)相當(dāng)不錯(cuò)的開發(fā)體驗(yàn)。
工具涉及到了幾個(gè)組件需要注意一下扩所,包括了vue路由围详,eslint,測(cè)試工具等祖屏。這些按需選擇安裝助赞。大寫字母表示是否默認(rèn)安裝。
如果不想因?yàn)槁酚啥Щ蟮脑捲祝梢圆贿x擇加入路由雹食。但是,eslint這個(gè)對(duì)新手來說相當(dāng)自虐的工具期丰,我是強(qiáng)烈推薦安裝的群叶。eslint提供多到可怕的規(guī)范化檢查,可以幫助避免寫出bug才怪钝荡。配合vscode的eslint插件街立,可以得到更好的體驗(yàn)。
創(chuàng)建完工程后可以得到類似于下圖的工程結(jié)構(gòu)
重點(diǎn)關(guān)注src文件夾里面的內(nèi)容埠通。
main.js里面new了一個(gè)vue實(shí)例赎离,元素(el)指向了id=‘a(chǎn)pp’的div。app.vue這個(gè)文件又引用了pie.vue這個(gè)組件端辱,而pie.vue又引用了mdiv.vue這個(gè)組件梁剔∷浠看起來和洋蔥一樣,一層一層又一層荣病。
寫第一個(gè)組件
有了上面的了解后码撰,可以動(dòng)手寫組件了。先從最里層開始寫起众雷。一個(gè).vue文件灸拍,可以認(rèn)為由三部分組成做祝。
<template>
<div class="mdiv">
<div class="head" @mousedown="mousedown">{{ title }}</div>
<div class="menu">
<div style="float: right; margin: 0 7px" @click="menuClick">
<span class="fas fa-ellipsis-v" v-show="isedit"></span>
</div>
<div style="float: right; margin: 0 3px" @click="expand">
<span class="fas" v-bind:class="{ 'fa-expand': !isexpand, 'fa-compress': isexpand }"></span>
</div>
<slot name="contextmenu"></slot>
</div>
<slot name="container"></slot>
<div class="resize" @mousedown="rmousedown"></div>
</div>
</template>
<script>
export default {
data () {
return {
title: ''
}
}
}
</script>
<style scoped>
</style>
第一個(gè)部分是template砾省,就是HTML了。這部分的內(nèi)容不多混槐,直接貼代碼编兄。
第二部分是script,就是組件的vue實(shí)例了声登。這個(gè)實(shí)例的el就指向了上面的template狠鸳。
第三部分是style,樣式悯嗓。加了scoped后件舵,這個(gè)標(biāo)簽里面的樣式就只在這個(gè)文件里面有效了。
HTML
在template里面有幾個(gè)內(nèi)容需要關(guān)注的脯厨。
@mousedown="mousedown"
這里的@是v-on的縮寫铅祸,用來綁定事件『衔洌可以是DOM的原生事件临梗,也可以是自定義事件。當(dāng)mousedown事件發(fā)生時(shí)稼跳,會(huì)調(diào)用綁定的mousedown方法盟庞。{{ title }}
是模板語(yǔ)法。當(dāng)title發(fā)生變化的時(shí)候汤善,頁(yè)面元素也會(huì)跟著變化什猖。v-show="isedit"
isedit是個(gè)布爾值,當(dāng)值為正(true)的時(shí)候红淡,這個(gè)標(biāo)簽就會(huì)顯示出來不狮,不然就隱藏起來。v-if
也可以得到類似的效果锉屈,區(qū)別可以看這里v-if vs v-show荤傲。v-bind:class="{ 'fa-expand': !isexpand, 'fa-compress': isexpand }"
用來綁定class,實(shí)現(xiàn)切換class颈渊。isexpand也是布爾值遂黍,當(dāng)值為真時(shí)终佛,<span class="fas" v-bind:class="{ 'fa-expand': !isexpand, 'fa-compress': isexpand }"></span>
將渲染成<span class="fas fa-compress"></span>
。<slot name="contextmenu"></slot>
slot是插槽雾家,父組件可以將內(nèi)容插到這個(gè)槽里面铃彰。這個(gè)是蠻好玩的特性。下篇文章還是說到芯咧。
script
這部分是vue的實(shí)例牙捉。實(shí)例有很多東西,有些是函數(shù)敬飒,有些事對(duì)象邪铲。
-
data
是個(gè)函數(shù),返回一個(gè)對(duì)象无拗〈剑可以簡(jiǎn)單的將對(duì)象的屬性看成組件的變量。
data () {
return {
isexpand: false,
// 空間位置相關(guān)
pos: {
left: this.outline[0],
top: this.outline[1],
height: this.outline[2],
width: this.outline[3]
},
posNew: {
left: this.outline[0],
top: this.outline[1],
height: this.outline[2],
width: this.outline[3]
},
// DIV相關(guān)臨時(shí)變量
down: null,
room: null
}
}
-
props
是一個(gè)對(duì)象英染,聲明了組件接受父組件的傳入的信息揽惹。!type是類型四康,如果寫成字符串(‘string’)則會(huì)報(bào)錯(cuò)搪搏。更具體的看Prop 驗(yàn)證。
props: {
name: {
type: String, // 類型
required: true // 是否必須
},
// [X, Y, W, H]
outline: {
type: Array,
required: true
},
isedit: {
type: Boolean,
default: false // 默認(rèn)值
}
}
- mounted 是一個(gè)實(shí)例生命周期鉤子闪金,當(dāng)el掛載后會(huì)調(diào)用這個(gè)函數(shù)疯溺。當(dāng)然,還有其他生命周期鉤子可以用毕泌。
mounted () {
this.$nextTick(() => {
this.$el.style.left = this.outline[0] + 'px' // x
this.$el.style.top = this.outline[1] + 'px' // y
this.$el.style.width = this.outline[2] + 'px' // w
this.$el.style.height = this.outline[3] + 'px' // h
})
}
- computed 計(jì)算屬性喝检,一個(gè)相當(dāng)好用的特性。title樣子上像是個(gè)函數(shù)撼泛,在template被使用挠说。當(dāng)name發(fā)生變化后,title會(huì)重新調(diào)用愿题。
computed: {
title () {
return this.name
}
}
- watch 偵聽器损俭,行為上和computed很像。但是潘酗,outline對(duì)應(yīng)了屬性杆兵。當(dāng)outline發(fā)生變化時(shí),會(huì)執(zhí)行這個(gè)函數(shù)仔夺。
watch: {
outline () {
this.outlineUpdate()
this.pos = {
left: this.outline[0],
top: this.outline[1],
height: this.outline[2],
width: this.outline[3]
}
this.$emit('mdiv', 'resize')
}
}
- emit 用于發(fā)送一個(gè)事件琐脏。第一個(gè)參數(shù)是事件名稱。vm.$emit
- methods 一些方法∪杖梗可以在組件中使用吹艇。
// 這個(gè)方法與一個(gè)div的click事件綁定,
// 當(dāng)事件發(fā)發(fā)生時(shí)昂拂,調(diào)用這個(gè)函數(shù)
// 用來顯示“全屏”效果
expand () {
this.isexpand = !this.isexpand
if (this.isexpand) { // isexpand === true 變?nèi)? this.$el.style.left = '1px'
this.$el.style.top = '1px'
this.$el.style.height = 'calc(100% - 2px)'
this.$el.style.width = 'calc(100% - 2px)'
} else {
this.$el.style.left = this.pos.left + 'px'
this.$el.style.top = this.pos.top + 'px'
this.$el.style.width = this.pos.width + 'px'
this.$el.style.height = this.pos.height + 'px'
}
}
下面這些代碼的主要功能時(shí)受神,鼠標(biāo)可以通過右下角拖拽縮放div。
// 縮放DIV
rmousedown (down) {
this.down = down
this.room = this.$el.parentElement.getBoundingClientRect()
this.room.width = this.room.width - this.pos.width - this.pos.left - 4
this.room.height = this.room.height - this.pos.height - this.pos.top - 4
console.log(this.room)
document.onmouseup = this.rmouseup
document.onmousemove = this.rmousemove
},
rmousemove (move) {
let diff = {x: move.clientX - this.down.clientX, y: move.clientY - this.down.clientY}
let x = diff.x < this.room.width ? diff.x : this.room.width
let y = diff.y < this.room.height ? diff.y : this.room.height
this.posNew.width = this.pos.width + x
this.posNew.height = this.pos.height + y
this.$el.style.width = this.posNew.width + 'px'
this.$el.style.height = this.posNew.height + 'px'
},
rmouseup () {
document.onmousemove = null
document.onmouseup = null
// 更新大小
Object.assign(this.pos, this.posNew)
this.$emit('mdiv', 'resize')
}
內(nèi)容比較多格侯,其他內(nèi)容到GitHub上面看鼻听。
style
樣式部分,沒什么好說的了联四。
第一個(gè)組件到這里就算實(shí)現(xiàn)了撑碴。然后就可以在其他組件里面使用,有點(diǎn)繼承的意思碎连。使用上類似這樣灰羽。
<template>
<mdiv></mdiv>
</template>
當(dāng)然,這樣是用不了的鱼辙,還差點(diǎn)東西。下一篇講從0開始寫Vue組件(下)
玫镐。