vue(2)

Vue組件化開發(fā)

  • 組件化開發(fā)的思想
  • 組件的注冊
  • 組件間的數(shù)據(jù)交互
  • 組件插槽的用法
  • Vue調(diào)試工具的用法

組件開發(fā)思想

  • 標(biāo)準(zhǔn)
  • 分治
  • 重用
  • 組合

組件化規(guī)范:Web Components(并非所有的瀏覽器都支持)

  • 我們希望盡可能多的重用代碼
  • 自定義組件的方式不太容易(html、css和js)
  • 多次使用組件可能導(dǎo)致沖突

Web Components通過創(chuàng)建封裝好功能的定制元素解決上述問題(Vue部分實(shí)現(xiàn)了上述規(guī)范)

組件注冊

Vue.component('組件名稱',{
    // 組件內(nèi)容
    data: '組件數(shù)據(jù)',
    template: '組件模板內(nèi)容'
})
<!-- 組件使用 -->
<div id="app">
    <h1>{{name}}</h1>
    <button-count></button-counter>
    <!-- 組件是可以重用的 -->
    <button-count></button-counter>
    <button-count></button-counter>
</div>
<script>
    // 定義一個(gè)名為 button-counter 的新組件
    Vue.component('button-counter', {
        data: function() {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">點(diǎn)擊{{count}}次</button>'
    })
</script>

組件注冊注意事項(xiàng):

  1. data必須是一個(gè)函數(shù) => 分析函數(shù)和普通對(duì)象的對(duì)比
  2. 組件模板內(nèi)容必須是單個(gè)根元素 => 分析演示實(shí)例的效果
  3. 組件模板內(nèi)容可以是模板字符串 => 模板字符串需要瀏覽器提供支持(ES6語法)
  4. 組建的命名方式
  • 短橫線方式Vue.component('my-component',{ /*...*/ }
  • 駝峰式Vue.component('myComponent',{ /*...*/ }
  • 如果使用駝峰式命名組件,那么在使用組件的時(shí)候坪蚁,只能在字符串模板中使用駝峰的方式命名組件,但是在普通的標(biāo)簽?zāi)0逯形偶仨毷褂枚虣M線的方式命名組件

局部組件注冊

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
    el: '#app',
    components: {
        'component-a' :componentA,
        'component-b' :componentB,
        'component-c' :componentC
    }
})
// 局部組件只能在其父組件中使用

Vue調(diào)試工具

  1. 克隆倉庫
  2. 安裝依賴包
  3. 構(gòu)建
  4. 打開Chrome擴(kuò)展頁面
  5. 選中開發(fā)者模式
  6. 加載已解壓的擴(kuò)展,選擇shells/chrome

組件間的數(shù)據(jù)交互

  1. 父組件向子組件傳值

    • 組件內(nèi)部通過props接收傳遞過來的值

      Vue.component('menu-item', {
          props: ['title'],
          template: '<div>{{title}}</div>'
      })
      
    • 父組件通過屬性將值傳遞給子組件

      <menu-item title="來自父組件傳遞的數(shù)據(jù)"></menu-item>
      <menu-item :title="title"></menu-item>
      
    • props屬性名規(guī)則

      • props中使用駝峰形式茂洒,模板中則需要使用短橫線的形式
      • 字符串形式的模板中則沒有這個(gè)限制
      <menu-item menu-title="hello"></menu-item>
      <script>
          Vue.component('menu-item', {
              // 在JavaScript中是駝峰式的
              props: ['menuTitle'],
              template: `<div>{{menuTitle}}`
          })
      </script>
      
      <div id="app">
          <h1>{{name}}</h1>
          <div>{{pmsg}}</div>
          <menu-item :menu-title="ptitle" content='hello'></menu-item>
      </div>
      <script>
          Vue.component('third-com', {
              props:['testTitle'],
              template:'<div>{{testTitle}}</div>'
          });
          Vue.component('menu-item', {
              props:['menuTitle'],
              template:'<div>{{menuTitle}}<third-com testTitle="hello"></third-com></div>'
          });
          let vm = new Vue({
              el:'#app',
              data:{
                  name:"myVue",
                  pmsg:'父組件的內(nèi)容',
                  ptitle:'動(dòng)態(tài)綁定的屬性'
              },
              methods: {
      
          }
          });
      </script>
      
    • props屬性值類型

      • 字符串 String
      • 數(shù)值 Number
      • 布爾值 Boolean
      • 數(shù)組 Array
      • 對(duì)象 Object
      <div id="app">
          <h1>{{name}}</h1>
          <div>{{pmsg}}</div>
          <!-- 不帶引號(hào)為字符串類型 -->
          <menu-item :pstr="pstr" :pnum="13" :pboo="true" :parr="parr" :pobj="pobj"></menu-item>
      </div>
      <script>
          Vue.component('menu-item', {
              props: ['pstr','pnum','pboo','parr','pobj'],
              template:`
                  <div>
                      <div>{{pstr}}</div>
                      <div>{{12 + pnum}}</div>
                      <div>{{pboo}}</div>
                      <ul>
                          <li :key="index" v-for="(item,index) in parr">{{item}}</li>
                      </ul>
                      <div>
                          <span>{{pobj.name}}</span>
                          <span>{{pobj.age}}</span>
                          <span>{{pobj.sex}}</span>
                      </div>
                  </div>`
          });
          let vm = new Vue({
              el: '#app',
              data: {
                  name: "myVue",
                  pmsg: '父組件的內(nèi)容',
                  pstr: 'hello',
                  parr:['蘋果','香蕉','哈密瓜'],
                  pobj:{
                      name:'張三',
                      age:19,
                      sex:'男'
                  }
              },
              methods: {
      
              }
          });
      </script>
      
  2. 子組件向父組件傳值

    • 子組件通過自定義事件向父組件傳遞消息
      <button v-on:click='$emit("enlarge-text")'>擴(kuò)大字體</button>

    • 父組件監(jiān)聽子組件事件
      <menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>

      <div id="app">
          <h1>{{name}}</h1>
          <div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div>
          <menu-item @enlarge-text="handle"></menu-item>
      </div>
      <script>
      /* 
      子組件向父組件傳遞數(shù)據(jù)-基本用法
          props傳遞數(shù)據(jù)原則:單項(xiàng)數(shù)據(jù)綁定
      */
      Vue.component('menu-item', {
          template:`
              <div>
                  <button @click="$emit('enlarge-text')">擴(kuò)大字體</button>
              </div>`
      });
      let vm = new Vue({
          el: '#app',
          data: {
              name: "myVue",
              pmsg: '父組件的內(nèi)容',
              fontSize: 10
          },
          methods: {
              handle:function() {
                  // 擴(kuò)大字體大小
                  this.fontSize+=10;
              }
          }
      });
      </script>
      
    • 子組件通過自定義事件向父組件傳遞信息
      <button v-on:click='$emit("enlarge-text", 0.1)'>擴(kuò)大字體</button>

    • 父組件監(jiān)聽子組件事件
      <menu-item v-on:enlarge-text='fontSize += $event'></menu-item>

      <div id="app">
          <h1>{{name}}</h1>
          <div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div>
          <!-- 不帶引號(hào)為字符串類型 -->
          <menu-item @enlarge-text="handle($event)"></menu-item>
      </div>
      <script>
          /* 
          子組件向父組件傳遞數(shù)據(jù)-基本用法
              props傳遞數(shù)據(jù)原則:單項(xiàng)數(shù)據(jù)綁定
          */
          Vue.component('menu-item', {
              template:`
                  <div>
                      <button @click="$emit('enlarge-text',5)">擴(kuò)大字體</button>
                      <button @click="$emit('enlarge-text',-5)">減小字體</button>
                  </div>`
          });
          let vm = new Vue({
              el: '#app',
              data: {
                  name: "myVue",
                  pmsg: '父組件的內(nèi)容',
                  fontSize: 10
              },
              methods: {
                  handle:function(val) {
                      // 擴(kuò)大字體大小
                      this.fontSize+=val;
                  }
              }
          });
      </script>
      
  3. 非父子組件間傳值(兄弟間組件傳值)

    • 單獨(dú)的事件中心管理組件間的通信 var eventHub = new Vue()

    • 監(jiān)聽事件與銷毀事件

      eventHub.$on('add-todo', addTab)
      eventHub.off('add-todo')
      
    • 觸發(fā)事件eventHub.$emit('add-todo', id)

    <div id="app">
        <h1>{{name}}</h1>
        <div>
            <button @click="handle">銷毀事件</button>
        </div>
        <text-tom></text-tom>
        <text-jerry></text-jerry>
    </div>
    <script type="text/javascript">
        // 兄弟組件間數(shù)據(jù)傳遞
        // 提供事件中心
        var hub = new Vue();
        Vue.component('text-tom', {
            data: function () {
                return {
                    num: 0
                }
            },
            template: `
                <div>
                    <div>Tom:{{num}}</div>
                    <div>
                        <button @click="handle">點(diǎn)擊</button>
                    </div>
                </div>`,
            methods: {
                handle: function () {
                    hub.$emit('jerry-event', 2)
                }
            },
            mounted: function () {
                // 監(jiān)聽事件
                hub.$on('tom-event', (val) => {
                    this.num += val;
                })
            }
        });
        Vue.component('text-jerry', {
            data: function () {
                return {
                    num: 0
                }
            },
            template: `
                <div>
                    <div>Jerry:{{num}}</div>
                    <div>
                        <button @click="handle">點(diǎn)擊</button>
                    </div>
                </div>`,
            methods: {
                handle: function () {
                    // 觸發(fā)兄弟組件的事件
                    hub.$emit('tom-event', 1)
                }
            },
            mounted: function () {
                // 監(jiān)聽事件
                hub.$on('jerry-event', (val) => {
                    this.num += val;
                })
            }
        });
        let vm = new Vue({
            el: '#app',
            data: {
                name: "myVue"
            },
            methods: {
                handle: function() {
                    hub.$off('tom-event');
                    hub.$off('jerry-event');
                }
            }
        });
    </script>
    

組件插槽

  • 父組件向子組件傳遞內(nèi)容

插槽基本用法

  1. 插槽位置

    <div id="app">
        <h1>{{name}}</h1>
        <alert-box>有bug!</alert-box>
        <alert-box>有一個(gè)警告!</alert-box>
        <alert-box></alert-box>
    </div>
    <script>
        Vue.component('alert-box', {
            template: `
                <div class="demo-alert-box">
                    <strong>Error!</strong>
                    <slot></slot>
                </div>`
        })
        let vm = new Vue({
            el: '#app',
            data: {
                name: "myVue"
            },
            methods: {
    
            }
        });
    </script>
    
  2. 具名插槽用法

    <!-- 插槽定義 -->
    <div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    </div>
    <!-- 插槽內(nèi)容 -->
    <base-layout>
        <h1 slot="header">標(biāo)題內(nèi)容</h1>
    
        <p>主要內(nèi)容1</p>
        <p>主要內(nèi)容2</p>
    
        <p slot="footer">底部內(nèi)容</p>
    </base-layout>
    
    <div id="app">
        <h1>{{name}}</h1>
        <base-layout>
            <p slot="header">標(biāo)題信息</p>
            <p>主要內(nèi)容1</p>
            <p>主要內(nèi)容2</p>
            <p slot="footer">底部信息</p>
        </base-layout>
        <base-layout>
            <template slot="header">
                <p slot="header">標(biāo)題信息</p>
                <p slot="header">標(biāo)題信息</p>
            </template>
            <p>主要內(nèi)容1</p>
            <p>主要內(nèi)容2</p>
            <template slot="footer">
                <p slot="header">尾部信息1</p>
                <p slot="header">尾部信息2</p>
            </template>
        </base-layout>
    </div>
    <script type="text/javascript">
        Vue.component('base-layout', {
            template: `
                <div>
                    <header>
                        <slot name="header"></slot>
                    </header>
                    <main>
                        <slot></slot>
                    </main>
                    <footer>
                        <slot name="footer"></slot>
                    </footer>
                </div>`
        });
        let vm = new Vue({
            el: '#app',
            data: {
                name: "myVue"
            },
            methods: {
    
            }
        });
    </script>
    
  3. 作用域插槽

  • 應(yīng)用場景:父組件對(duì)子組件的內(nèi)容進(jìn)行加工處理

    <!-- 插槽定義 -->
    <ul>
        <li v-for="item in list" v-bind:key="item.id">
            <slot v-bind:item="item">
                {{item.name}}
            </slot>
        </li>
    </ul>
    <!-- 插槽內(nèi)容 -->
    <fruit-list v-bind:list="list">
        <template slot-scope="slotProps">
            <strong v-if="slotProps.item.current">
                {{slotProps.item.text}}
            </strong>
        </template>
    </fruit-list>
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孟岛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子获黔,更是在濱河造成了極大的恐慌,老刑警劉巖在验,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玷氏,死亡現(xiàn)場離奇詭異,居然都是意外死亡腋舌,警方通過查閱死者的電腦和手機(jī)盏触,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赞辩,你說我怎么就攤上這事雌芽。” “怎么了辨嗽?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵世落,是天一觀的道長先馆。 經(jīng)常有香客問我害幅,道長度宦,這世上最難降的妖魔是什么偶芍? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任葫哗,我火速辦了婚禮谅辣,結(jié)果婚禮上凄吏,老公的妹妹穿的比我還像新娘铸敏。我一直安慰自己杈帐,他們只是感情好体箕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挑童,像睡著了一般累铅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炮沐,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天争群,我揣著相機(jī)與錄音,去河邊找鬼大年。 笑死换薄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的翔试。 我是一名探鬼主播轻要,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼垦缅!你這毒婦竟也來了冲泥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤壁涎,失蹤者是張志新(化名)和其女友劉穎凡恍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怔球,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚼酝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竟坛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闽巩。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钧舌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涎跨,到底是詐尸還是另有隱情洼冻,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布隅很,位于F島的核電站撞牢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏外构。R本人自食惡果不足惜普泡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望审编。 院中可真熱鬧撼班,春花似錦、人聲如沸垒酬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勘究。三九已至矮湘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間口糕,已是汗流浹背缅阳。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留景描,地道東北人十办。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像超棺,于是被迫代替她去往敵國和親向族。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351