vue系列4:vue組件和模塊


1、vue組件和模塊的區別

什么是組件: 組件的出現,就是為了拆分Vue實例的代碼量的,能夠讓我們以不同的組件,來划分不同的功能模塊,將來我們需要什么樣的功能,就可以去調用對應的組件即可;
組件化和模塊化的不同:

  • 模塊化: 是從代碼邏輯的角度進行划分的;方便代碼分層開發,保證每個功能模塊的職能單一;
  • 組件化: 是從UI界面的角度進行划分的;前端的組件化,方便UI組件的重用;

2、組件創建方式1

<body>
  <div id="app">
    <!-- 如果要使用組件,直接,把組件的名稱,以 HTML 標簽的形式,引入到頁面中,即可 -->
    <mycom1></mycom1>
  </div>

  <script>
    // 1.1 使用 Vue.extend 來創建全局的Vue組件
    // var com1 = Vue.extend({
    //   template: '<h3>這是使用 Vue.extend 創建的組件</h3>' // 通過 template 屬性,指定了組件要展示的HTML結構
    // })
    // 1.2 使用 Vue.component('組件的名稱', 創建出來的組件模板對象)
    // Vue.component('myCom1', com1)
    // 如果使用 Vue.component 定義全局組件的時候,組件名稱使用了 駝峰命名,則在引用組件的時候,需要把 大寫的駝峰改為小寫的字母,同時,兩個單詞之前,使用 - 鏈接;
    // 如果不使用駝峰,則直接拿名稱來使用即可;
    // Vue.component('mycom1', com1)

    // Vue.component 第一個參數:組件的名稱,將來在引用組件的時候,就是一個 標簽形式 來引入 它的
    // 第二個參數: Vue.extend 創建的組件  ,其中 template 就是組件將來要展示的HTML內容
    Vue.component('mycom1', Vue.extend({
      template: '<h3>這是使用 Vue.extend 創建的組件</h3>'
    }))

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });
  </script>
</body>

3、組件的創建方式2

<body>
  <div id="app">
    <!-- 還是使用 標簽形式,引入自己的組件 -->
    <mycom2></mycom2>
  </div>

  <script>
    // 注意:不論是哪種方式創建出來的組件,組件的 template 屬性指向的模板內容,必須有且只能有唯一的一個根元素
    Vue.component('mycom2', {
      template: '<div><h3>這是直接使用 Vue.component 創建出來的組件</h3><span>123</span></div>'
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });
  </script>
</body>

4、組件的創建方式3

<body>
  <div id="app">
    <mycom3></mycom3>
    <!-- <login></login> -->
  </div>

  <div id="app2">
    <mycom3></mycom3>
    <login></login>
  </div>

  <!-- 在 被控制的 #app 外面,使用 template 元素,定義組件的HTML模板結構  -->
  <template id="tmpl">
    <div>
      <h1>這是通過 template 元素,在外部定義的組件結構,這個方式,有代碼的只能提示和高亮</h1>
      <h4>好用,不錯!</h4>
    </div>
  </template>

  <template id="tmpl2">
    <h1>這是私有的 login 組件</h1>
  </template>

  <script>
    Vue.component('mycom3', {
      template: '#tmpl'
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });


    var vm2 = new Vue({
      el: '#app2',
      data: {},
      methods: {},
      filters: {},
      directives: {},
      components: { // 定義實例內部私有組件的
        login: {
          template: '#tmpl2'
        }
      },

      beforeCreate() { },
      created() { },
      beforeMount() { },
      mounted() { },
      beforeUpdate() { },
      updated() { },
      beforeDestroy() { },
      destroyed() { }
    })
  </script>
</body>

5、組件中的data和methods

<body>
  <div id="app">
    <mycom1></mycom1>
  </div>
  <script>
    // 1. 組件可以有自己的 data 數據
    // 2. 組件的 data 和 實例的 data 有點不一樣,實例中的 data 可以為一個對象,但是 組件中的 data 必須是一個方法
    // 3. 組件中的 data 除了必須為一個方法之外,這個方法內部,還必須返回一個對象才行;
    // 4. 組件中 的data 數據,使用方式,和實例中的 data 使用方式完全一樣!!!
    Vue.component('mycom1', {
      template: '<h1>這是全局組件 --- {{msg}}</h1>',
      data: function () {
        return {
          msg: '這是組件的中data定義的數據'
        }
      }
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });
  </script>
</body>

6、組件-why components data must be a function

<body>
  <div id="app">
    <counter></counter>
    <hr>
    <counter></counter>
    <hr>
    <counter></counter>
  </div>


  <template id="tmpl">
    <div>
      <input type="button" value="+1" @click="increment">
      <h3>{{count}}</h3>
    </div>
  </template>

  <script>
    var dataObj = { count: 0 }

    // 這是一個計數器的組件, 身上有個按鈕,每當點擊按鈕,讓 data 中的 count 值 +1
    Vue.component('counter', {
      template: '#tmpl',
      data: function () {
        // return dataObj  //如果是這樣,如果放置三個組件,三個按鈕分別點擊,每個都會增長
        return { count: 0 }
      },
      methods: {
        increment() {
          this.count++
        }
      }
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });
  </script>
</body>

7、組件切換方式一

<body>
  <div id="app">
    <a href="" @click.prevent="flag=true">登錄</a>
    <a href="" @click.prevent="flag=false">注冊</a>

    <login v-if="flag"></login>
    <register v-else="flag"></register>

  </div>

  <script>
    Vue.component('login', {
      template: '<h3>登錄組件</h3>'
    })

    Vue.component('register', {
      template: '<h3>注冊組件</h3>'
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        flag: false
      },
      methods: {}
    });
  </script>
</body>

8、組件切換方式二

<body>
  <div id="app">
    <a href="" @click.prevent="comName='login'">登錄</a>
    <a href="" @click.prevent="comName='register'">注冊</a>

    <!-- Vue提供了 component ,來展示對應名稱的組件 -->
    <!-- component 是一個占位符, :is 屬性,可以用來指定要展示的組件的名稱 -->
    <component :is="comName"></component>

    <!-- 總結:當前學習了幾個 Vue 提供的標簽了??? -->
    <!-- component,  template,  transition,  transitionGroup  -->

  </div>

  <script>
    // 組件名稱是 字符串
    Vue.component('login', {
      template: '<h3>登錄組件</h3>'
    })

    Vue.component('register', {
      template: '<h3>注冊組件</h3>'
    })

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        comName: 'login' // 當前 component 中的 :is 綁定的組件的名稱
      },
      methods: {}
    });
  </script>
</body>

9、父組件向子組件傳值

<body>
  <div id="app">
    <!-- 父組件,可以在引用子組件的時候, 通過 屬性綁定(v-bind:) 的形式, 把 需要傳遞給 子組件的數據,以屬性綁定的形式,傳遞到子組件內部,供子組件使用 -->
    <com1 v-bind:parentmsg="msg"></com1>
  </div>

  <script>
    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        msg: '123 啊-父組件中的數據'
      },
      methods: {},

      components: {
        // 結論:經過演示,發現,子組件中,默認無法訪問到 父組件中的 data 上的數據 和 methods 中的方法
        com1: {
          data() { // 注意: 子組件中的 data 數據,並不是通過 父組件傳遞過來的,而是子組件自身私有的,比如: 子組件通過 Ajax ,請求回來的數據,都可以放到 data 身上;
            // data 上的數據,都是可讀可寫的;
            return {
              title: '123',
              content: 'qqq'
            }
          },
          template: '<h1 @click="change">這是子組件 --- {{ parentmsg }}</h1>',
          
          // 注意: 組件中的 所有 props 中的數據,都是通過 父組件傳遞給子組件的
          // props 中的數據,都是只讀的,無法重新賦值
          props: ['parentmsg'], // 把父組件傳遞過來的 parentmsg 屬性,先在 props 數組中,定義一下,這樣,才能使用這個數據
          directives: {},
          filters: {},
          components: {},
          methods: {
            change() {
              this.parentmsg = '被修改了'
            }
          }
        }
      }
    });
  </script>
</body>

10、父組件把方法傳遞給子組件(子組件通過事件綁定機制,向父組件傳遞消息)

<body>
  <div id="app">
    <!-- 父組件向子組件 傳遞 方法,使用的是 事件綁定機制; v-on, 當我們自定義了 一個 事件屬性之后,那么,子組件就能夠,通過某些方式,來調用 傳遞進去的 這個 方法了 -->
    <com2 @func="show"></com2>
  </div>

  <template id="tmpl">
    <div>
      <h1>這是 子組件</h1>
      <input type="button" value="這是子組件中的按鈕 - 點擊它,觸發 父組件傳遞過來的 func 方法" @click="myclick">
    </div>
  </template>

  <script>

    // 定義了一個字面量類型的 組件模板對象
    var com2 = {
      template: '#tmpl', // 通過指定了一個 Id, 表示 說,要去加載 這個指定Id的 template 元素中的內容,當作 組件的HTML結構
      data() {
        return {
          sonmsg: { name: '小頭兒子', age: 6 }
        }
      },
      methods: {
        myclick() {
          // 當點擊子組件的按鈕的時候,如何 拿到 父組件傳遞過來的 func 方法,並調用這個方法???
          //  emit 英文原意: 是觸發,調用、發射的意思
          // this.$emit('func123', 123, 456)
          this.$emit('func', this.sonmsg)
        }
      }
    }


    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        datamsgFormSon: null
      },
      methods: {
        show(data) {
          console.log('子組件的值未傳遞給父組件時 --- ' + this.datamsgFormSon)
          console.log('調用了父組件身上的 show 方法: --- ' + data.name)
          console.log(data);
          this.datamsgFormSon = data
          console.log('子組件的值傳遞給父組件后: --- ' + this.datamsgFormSon)

          this.datamsgFormSon = data
        }
      },

      components: {
        com2
        // com2: com2
      }
    });
  </script>
</body>

11、組件案例------評論列表

<body>
  <div id="app">


    <cmt-box @func="loadComments"></cmt-box>


    <ul class="list-group">
      <li class="list-group-item" v-for="item in list" :key="item.id">
        <span class="badge">評論人: {{ item.user }}</span>
        {{ item.content }}
      </li>
    </ul>


  </div>


  <template id="tmpl">
    <div>

      <div class="form-group">
        <label>評論人:</label>
        <input type="text" class="form-control" v-model="user">
      </div>

      <div class="form-group">
        <label>評論內容:</label>
        <textarea class="form-control" v-model="content"></textarea>
      </div>

      <div class="form-group">
        <input type="button" value="發表評論" class="btn btn-primary" @click="postComment">
      </div>

    </div>
  </template>

  <script>

    var commentBox = {
      data() {
        return {
          user: '',
          content: ''
        }
      },
      template: '#tmpl',
      methods: {
        postComment() { // 發表評論的方法
          // 分析:發表評論的業務邏輯
          // 1. 評論數據存到哪里去???   存放到了 localStorage 中  localStorage.setItem('cmts', '')
          // 2. 先組織出一個最新的評論數據對象
          // 3. 想辦法,把 第二步中,得到的評論對象,保存到 localStorage 中:
          //  3.1 localStorage 只支持存放字符串數據, 要先調用 JSON.stringify 
          //  3.2 在保存 最新的 評論數據之前,要先從 localStorage 獲取到之前的評論數據(string), 轉換為 一個  數組對象, 然后,把最新的評論, push 到這個數組
          //  3.3 如果獲取到的 localStorage 中的 評論字符串,為空不存在, 則  可以 返回一個 '[]'  讓 JSON.parse 去轉換
          //  3.4  把 最新的  評論列表數組,再次調用 JSON.stringify 轉為  數組字符串,然后調用 localStorage.setItem()
          //JSON.stringify()的作用是將 JavaScript 對象轉換為 JSON 字符串,而JSON.parse()可以將JSON字符串轉為一個對象。
          var comment = { id: Date.now(), user: this.user, content: this.content }

          // 從 localStorage 中獲取所有的評論
          var list = JSON.parse(localStorage.getItem('cmts') || '[]')
          list.unshift(comment)
          // 重新保存最新的 評論數據
          localStorage.setItem('cmts', JSON.stringify(list))

          this.user = this.content = ''

          // this.loadComments() // ?????
          this.$emit('func')
        }
      }
    }

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        list: [
          { id: Date.now(), user: '李白', content: '天生我材必有用' },
          { id: Date.now(), user: '江小白', content: '勸君更盡一杯酒' },
          { id: Date.now(), user: '小馬', content: '我姓馬, 風吹草低見牛羊的馬' }
        ]
      },
      beforeCreate(){ // 注意:這里不能調用 loadComments 方法,因為在執行這個鈎子函數的時候,data 和 methods 都還沒有被初始化好

      },
      created(){
        this.loadComments()
      },
      methods: {
        loadComments() { // 從本地的 localStorage 中,加載評論列表
          var list = JSON.parse(localStorage.getItem('cmts') || '[]')
          this.list = list
        }
      },
      components: {
        'cmt-box': commentBox
      }
    });
  </script>
</body>

12、ref獲取DOM元素和組件

<body>
  <div id="app">
    <input type="button" value="獲取元素" @click="getElement" ref="mybtn">
    <h3 id="myh3" ref="myh3">哈哈哈, 今天天氣太好了!!!</h3>
    <hr>
    <login ref="mylogin"></login>
  </div>

  <script>
    var login = {
      template: '<h1>登錄組件</h1>',
      data() {
        return {
          msg: 'son msg'
        }
      },
      methods: {
        show() {
          console.log('調用了子組件的方法')
        }
      }
    }

    // 創建 Vue 實例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {
        getElement() {
          // console.log(document.getElementById('myh3').innerText)

          //  ref  是 英文單詞 【reference】   值類型 和 引用類型  referenceError
          // console.log(this.$refs.myh3.innerText)

           console.log(this.$refs.mylogin.msg)
           this.$refs.mylogin.show()
        }
      },
      components: {
        login
      }
    });
  </script>
</body>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM