Vue組件化初體驗

認識組件

組件化開發:

? 將一個完成的頁面,劃分成一個個的組件,最終由一個個組件來完成整個頁面你的開發,這個過程就是組件化開發

優勢:復用!!

? 也就是說組件只需要寫一次,然后,用到組件的地方,只需要拿過去用就可以了

組成

一個組件由三部分組成:HTML+CSS+JS

兩種注冊組件的方式:

? 1 全局組件

? 2 局部組件

注冊全局組件:

? 第一個參數:表示組件名稱

? 第二個參數:是一個配置對象,這個配置對象類似于 Vue 構造函數中使用的配置對象

? 也就是說:在 Vue 構造函數中能夠使用的配置項,幾乎都可以用在組件中

template 作用:指定組件模板

? 注意:只能出現一個根節點

通過 data 指定組件中用到的數據

? 注意:組件中的數據data,是一個方法,通過方法的返回對象來作為組件數據

我的第一個全局組件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    <div id="app">
      <!-- 使用組件: -->
      <hello></hello> <hello></hello> <hello></hello> <hello></hello>
    </div>

    <script src="./vue.js"></script>
    <script>
      /* 
        兩種注冊組件的方式:
        1 全局組件
        2 局部組件

        一個組件由三部分組成:HTML+CSS+JS
      */

      // 注冊全局組件:
      // 第一個參數:表示組件名稱
      // 第二個參數:是一個配置對象,這個配置對象類似于 Vue 構造函數中使用的配置對象
      //  也就是說:在 Vue 構造函數中能夠使用的配置項,幾乎都可以用在組件中
      Vue.component('hello', {
        // template 作用:指定組件模板
        // 注意:只能出現一個根節點
        template: `
          <div>
            <h1>這是我的第一個組件 - Hello 組件</h1>
            <span @click="fn">{{ msg }}</span>
          </div>
        `,

        // 通過 data 指定組件中用到的數據
        // 注意:組件中的數據data,是一個方法,通過方法的返回對象來作為組件數據
        data() {
          return {
            msg: 'Vue Component data'
          }
        },

        // 鉤子函數
        created() {
          console.log('created 鉤子函數執行了')
        },
        // 方法
        methods: {
          fn() {
            console.log('方法執行了')
          }
        }
      })
      const vm = new Vue({
        el: '#app',
        data: {}
      })
    </script>
  </body>
</html>

注冊局部組件

? 通過配置項 components: {}

//html
 <div id="app">
      <item></item>
      <wang></wang>
  </div>
  
  //js
   Vue.component('wang',{
      template:`
      <p>我是王婷,<ting></ting></p>
      `,
      components:{
        //組件名稱
        ting:{
          //組件模板
          template:`
            <span>我最美,{{wt}}</span>
          `,
          //組件使用的數據
          data(){
            return {
              wt:'確認過眼神,這是真的'
            }
          }
        }
      }
    });
    const vm = new Vue({
      el: '#app',
      data: {
        msg:''
      },
      components:{
        item:{
          template:`
            <p>我是一個局部的組件:{{chang}}</p>
          `,
          data(){
            return{
              chang:'驗證通過'
            }
          }
        }
      }
    })
兩中組件的區別

? 1.全局組件可以在任意的地方使用

? 2.局部組件只能在所屬組件的 模板 中使用

使用組件

組件使用中的細節點:

? 表單/ul/ol等中指定的標簽

產生的原因:在tbody中只能使用tr標簽,使用其他的標簽,瀏覽器解析的時候,會把其他標簽作為table外部標簽解析出去,結構就會發生分離,ul和ol也是如此

使用is解決問題,例如tr標簽

//html
<table>
    <tbody>
        <tr is=chang></chang>
    </tbody>
</table>

//js

Vue.component('chang', {
    template: `
        <tr>
            <td>常杰</td>
            <td>李想</td>
            <td>老丁</td>
        </tr>
    `
});

使用ref屬性獲取dom對象

//html
  <div id="app">

    <table>
      <tbody>
        <tr is=chang>
          </chang>
        
      </tbody>
    </table>
  </div>

//js
Vue.component('chang', {
      template: `
        <tr>
          <td ref='hello' @click="handler">{{current}}</td>
        </tr>
      `,
      data(){
        return{
          current:'常杰'
        }
      },
      methods:{
        handler(){
          // alert('你觸發了點擊事件');
          console.log(this.$refs.hello)
        }
      }
    });
組件通訊:

? 組件是一個獨立且封閉的個體,也就是說:默認情況下,組件只能使用自身的數據,而不能使用外部的數據

? 但是,在組件化開發過程中,兩個組件通訊( 也就是兩個組件使用對方法的數據 ),是很常見的問題。

? 這種問題就需要通過 組件通訊 機制來解決

組件通訊的三種情況:

? 1 父組件 傳遞數據給 子組件

? 2 子組件 傳遞數據給 父組件

? 3 非父子組件(兄弟組件)

父 -->子通訊:

? 父組件: Vue實例

? 子組件: child組件

步驟:

? 1 在子組件標簽中添加要傳遞的屬性

  <child msg="123"></child> msg就是要傳遞的屬性
  <child :msg="parentMsg"></child> 表示傳遞動態數據給子組件

? 2 在子組件中通過 props 顯示指定要接受的屬性

? props: ['msg']

? 3 此時,就可以在子組件中直接使用 msg 這個數據了

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .parent {
        background-color: hotpink;
        padding: 50px;
      }

      .child {
        background-color: #daa520;
        height: 100px;
      }
    </style>
  </head>

  <body>
    <div id="app" class="parent">
      父組件:{{ parentMsg }}
      <!-- 渲染子組件: -->
      <!-- <child msg="123"></child> -->
      <!-- <child msg="parentMsg"></child> -->

      <!-- 表示將父組件中的數據 parentMsg 傳遞給子組件 -->
      <child :msg="parentMsg"></child>
    </div>

    <script src="./vue.js"></script>
    <script>
      // 注冊子組件
      Vue.component('child', {
        template: `
          <div class="child">
            <p>這是子組件 - {{ msg }}</p>
          </div>
        `,

        // 組件中通過 props 配置項,來顯示指定要接受的數據
        props: ['msg']
      })

      const vm = new Vue({
        el: '#app',
        data: {
          parentMsg: '這是父組件中的數據'
        }
      })
    </script>
  </body>
</html>

子 -->父通訊

·思路:父組件提供一個方法,讓子組件調用,子組件調用方法的時候將數據作為參數傳遞,這樣,父組件就拿到子組件中傳遞過來的數據了

? function parent(data) {

? console.log('子組件中傳遞過來的數據:', data)

? }

? 子組件調用方法: parent( '要傳遞給父組件的數據' )

實現子組件給父組件傳值的過程

? 1.首先給父組件注冊一個方法,同時在data設置一個變量準備接收子組件傳出的值

? 2.給子組件的標簽上綁定自定義事件,并把方法作為事件函數傳入

? 3.在子組件中設置模板。在模板中設置事件,觸發子組件的方法,在子組件的方法中,獲取到傳入的自定義事件,并且觸發這個事件,傳遞參數

? 4.子組件觸發這個方法,并把數據作為方法的參數傳出

? 5.在父組件中處理觸發事件的操作

//html
  <div id="app">

    我兒子給我發的信息:{{msg}}
    <!-- 2.給子組件的標簽上綁定自定義事件,并把方法作為事件函數傳入 -->
    <son @pmsg="fn"></son>
  </div>
  
  //js
  Vue.component('son',{
      // 3.在子組件中設置模板。在模板中設置事件,觸發子組件的方法,在子組件的方法中,獲取到傳入的自定義事件,并且觸發這個事件,傳遞參數
      template:`
        <p>我要給老爸發信息
          <button @click="send">發送信息</button>
        </p>
      `,
      // 4.子組件觸發這個方法,并把數據作為方法的參數傳出
      methods:{
        send(){
          this.$emit('pmsg',"老爸,我資金有點....")
        }
      }
    });

    const vm = new Vue({
      el: '#app',
      data: {
        msg:'沒啥用,就占個位'
      },
      // 1.首先給父組件注冊一個方法,同時在data設置一個變量準備接收子組件傳出的值
      methods:{
        // 5.在父組件中處理觸發事件的操作
        fn(data){
          this.msg = data
        }
      }
    })
小案例:

計數器實現的步驟

  • 1.首先創建一個子組件count
  • 2.在組件中創建模板,在模板中綁定事件handler,插入數據num
  • 3.在組件中創建模板中調用的方法handler
  • 4.在模板中設置數據num
  • 5.在組件標簽上注冊事件change,并綁定handlerChange方法(非常重要)
  • 6.在組件標簽上添加屬性ref為one/two(非常重要)
  • 7.在Vue實例中,添加方法handlerChange,并通過this.$refs.綁定的名稱獲取數據
  • 8.獲取到子組件的數據進行操作
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
      <!-- 5.在組件標簽上注冊事件change,并綁定handlerChange方法(非常重要) -->
      <!-- 6.在組件標簽上添加屬性ref為one/two(非常重要) -->
    <count ref="one" @change="handlerChange"></count>
    <count ref="two" @change="handlerChange"></count>

    <div>{{total}}</div>
  </div>
  <script src="./vue.js"></script>
  <script>
    // 1.首先創建一個子組件count
    Vue.component('count',{
      // 2.在組件中創建模板,在模板中綁定事件handler,插入數據num
      template:`
        <div @click="handler">{{num}}</div>
      `,
      // 4.在模板中設置數據num
      data(){
        return {
          num: 0
        }
      },
      // 3.在組件中創建模板中調用的方法handler
      methods:{
        handler(){
          this.num++;
          this.$emit("change")
        }
      }
    });
    const vm = new Vue({
      el: '#app',
      data: {
        total: 0
      },
      // 7.在Vue實例中,添加方法handlerChange,并通過this.$refs.綁定的名稱獲取數據
      methods:{
        handlerChange(){
          // console.log("handlerChange執行了")
          // console.log(this.$refs.one.num)
          // console.log(this.$refs.two.num)

          // 8.獲取到子組件的數據進行操作
          this.total = this.$refs.one.num + this.$refs.two.num
        }
      }
    })
  </script>
</body>

</html>
其他通訊(非父子)

思路:

1 創建一個事件總線(空的Vue實例 bus)

? 2 哪個組件要接收數據,就注冊事件

? bus.$on(事件名稱, () => {})

? 3 哪個組件要傳遞數據,就觸發事件

? bus.$emit(事件名稱, 要傳遞的數據)

注意: 注冊和觸發事件的 bus 是同一個,事件名稱也要相同

實際上,不管兩個組件是什么關系,都可以通過 bus 方式來實現通訊!

步驟:

? 1.首先創建一個 空的vue實例的對象 bus

? 2.然后創建兩個組件,一個臨時用于接收 (wang) ,一個臨時用于發送數據 (chang)

? 3.給兩個組件設置好模板內容

? 4. 組件chang設置方法,在方法中通過bus.$emit獲取事件,并設置觸發事件的參數

? 5.在組件wang的鉤子函數created中聲明創建事件listen,并設置獲取到參數后的處理

? 注意點:雖然用不到vm但是,必須聲明創建這個實例,只有指定了vue的邊界,代碼才能生效

//html
    <div id="app">
      <chang></chang>
      <wang></wang>
    </div>
    
//js
 // 空Vue實例
      // 事件總線
      // 1.首先創建一個 空的vue實例的對象 即事件總線bus
      let bus = new Vue();
      // 2.然后創建兩個組件,一個臨時用于接收 (wang) ,一個臨時用于發送數據 (chang)
      Vue.component('chang',{
        // 3.給兩個組件設置好模板內容
        template:`
        <p>我是常杰,我想對王婷說:<button @click="fn">加密發送</button></p>
        `,
        // 4. 組件chang設置方法,在方法中通過bus.$emit獲取事件,并設置觸發事件的參數
        methods:{
          fn(){
            bus.$emit('listen','那天我一直在等你')
          }
        }
      });
      Vue.component('wang',{
        template:`
        <p>我是王婷,常杰對我說:{{msg}}</p>
        `,
        data(){
          return {
            msg:'接收信息中,請等待...'
          }
        },
        // 5.在組件wang的鉤子函數created中聲明創建事件listen,并設置獲取到參數后的處理
        created(){
          bus.$on('listen',data=>{
            this.msg = data
          })
        }
      });
    //沒有用到數據,但是必須聲明
      const vm = new Vue({
        el:"#app",
        data:{
        }
      });

細節補充

props的屬性

? props:是只讀的,在組件中使用的時候,只能讀取,不能修改props的值( 賦值

)如果修改這個值,會報錯!!!

? 如果props是一個引用類型的數據,不能直接賦值,但是,可以修改引用類型中某個屬性的值。

單向數據流:

? 是說組件之間數據流動方向是從 父組件流動到 子組件

? 父組件可以通過 props 將數據傳遞給子組件,并且,當父組件中的這個數據改變

后,這個改變后的數據會自動的再流動到子組件中。也就是說:子組件會自動接收到最

新的props數據,并且自動更新

? 總結:

? 1.props是只讀的屬性,只能讀取props的值,而不能直接修改props的值

? 如果是引用類型(對象、數組),可以直接修改對象中某個屬性的值,但是,如果要求很嚴謹,也不應該直接修改對象中某個屬性的值!!!

? 2.單項數據流: 兩個組件之間的數據流動方向,方向是: 父 -> 子

命名

HTML 標簽或屬性都是不區分大小寫的(大小寫不敏感的)

? 不管你寫的是大寫字母的標簽名或屬性名,還是小寫的,最終,都會被轉化為小寫字母

? 同樣的,在 Vue 中,給組件傳遞屬性的時候,如果屬性名中包含大寫字母,在解析的時候,也會被轉化為小寫字母,再作為屬性傳遞給組件

? 如何給props命名:

? 1 使用純小寫字母

? <hello :childmsg="parentMsg"></hello>

? props: ['childmsg']

? 2 傳遞屬性的時候,使用短橫線連接多個單詞,在子組件中通過 駝峰命名法 來接收這個數據(規范)

? 傳遞(短橫線連接) <hello :child-msg="parentMsg"></hello>

? 接收(駝峰命名法) props: ['childMsg']

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容