從0開始寫Vue組件(上)

好一段時(shí)間沒寫文章了喷楣。嗯趟大,之前欠的nodemcu的文章,我會(huì)找時(shí)間補(bǔ)上的铣焊。剛好項(xiàng)目組推新的固件逊朽,加入幾個(gè)新的模塊。放心曲伊,我一定會(huì)更新那個(gè)系列的文章的叽讳,只有有時(shí)間相信未來一段時(shí)間都沒有的話。??

這回帶來的是有關(guān)寫Vue組件(.vue)的文章坟募。主要會(huì)涉及的內(nèi)容包括props岛蚤,datamethods等一系列概念懈糯。力爭(zhēng)用最簡(jiǎn)單的語(yǔ)言讓像我一樣的萌新可以快速上手寫出Vue組件來涤妒。跟著本來走一遍可以得到下面的效果。GitHub

目標(biāo)

創(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)。


vue-cli

工具涉及到了幾個(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)

工程結(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組件(下)
玫镐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末倒戏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恐似,更是在濱河造成了極大的恐慌杜跷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矫夷,死亡現(xiàn)場(chǎng)離奇詭異葛闷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)双藕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門淑趾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人忧陪,你說我怎么就攤上這事扣泊。” “怎么了嘶摊?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵延蟹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我叶堆,道長(zhǎng)阱飘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮沥匈,結(jié)果婚禮上果录,老公的妹妹穿的比我還像新娘。我一直安慰自己咐熙,他們只是感情好弱恒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棋恼,像睡著了一般返弹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爪飘,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天义起,我揣著相機(jī)與錄音,去河邊找鬼师崎。 笑死默终,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的犁罩。 我是一名探鬼主播齐蔽,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼床估!你這毒婦竟也來了含滴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤丐巫,失蹤者是張志新(化名)和其女友劉穎谈况,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體递胧,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碑韵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缎脾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祝闻。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赊锚,靈堂內(nèi)的尸體忽然破棺而出治筒,到底是詐尸還是另有隱情,我是刑警寧澤舷蒲,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布耸袜,位于F島的核電站,受9級(jí)特大地震影響牲平,放射性物質(zhì)發(fā)生泄漏堤框。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜈抓。 院中可真熱鬧启绰,春花似錦、人聲如沸沟使。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腊嗡。三九已至着倾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燕少,已是汗流浹背卡者。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留客们,地道東北人崇决。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像底挫,于是被迫代替她去往敵國(guó)和親恒傻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容凄敢,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容碌冶。關(guān)于...
    云之外閱讀 5,045評(píng)論 0 29
  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,202評(píng)論 0 6
  • 下載安裝搭建環(huán)境 可以選npm安裝,或者簡(jiǎn)單下載一個(gè)開發(fā)版的vue.js文件 瀏覽器打開加載有vue的文檔時(shí)涝缝,控制...
    冥冥2017閱讀 6,029評(píng)論 0 42
  • Life Switch appliance。嗯嗯譬重,又開始思考所謂的感悟問題拒逮,如果從生活的階段來看,自己應(yīng)該沒長(zhǎng)進(jìn)多...
    YKCA閱讀 191評(píng)論 0 0
  • 好的產(chǎn)品得做好兩件事:特點(diǎn)和細(xì)節(jié)臀规。特點(diǎn)用于將人們吸引到你的產(chǎn)品這來滩援。細(xì)節(jié) 則是讓用戶保持使用這項(xiàng)產(chǎn)品的原因,正是細(xì)...
    粥一閱讀 580評(píng)論 0 6