day 83 Vue學習三之vue組件

  • 2020 年 1 月 16 日
  • 筆記

本節目錄

一 什麼是組件

  首先給大家介紹一下組件(component)的概念

  我們在進行vue開發的時候,還記得我們自己創建的vm對象嗎,這個vm對象我們稱為一個大組件,根組件(頁面上叫Root),在一個網頁的開發中,根據網頁上的功能區域我們又可以細分成其他組件,或稱為子組件,看下面的圖解:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>test vue</title>  </head>  <body>    <div id="app">      <div>{{ msg }}</div>      <div v-text="msg"></div>      <div v-html="msg"></div>    </div>  <hr>      <script src="vue.js"></script>  <script>     //組件      new Vue({          el:'#app',          data(){              return{                  msg:'<h2>超</h2>',              }          }      })    </script>  </body>  </html>

  以vue官網來看,vue官網是用vue開發的:

    每個組件中都有對應的data(),methods,watch等屬性功能,組件是為了功能模組化,為了解耦,每個組件有自己的數據屬性,監聽自己的數據屬性等操作。

    後面我們學習組件會知道組件是可以嵌套的,那麼就看看圖解組件嵌套的組件樹,及數據流向,數據是單項數據流 ,數據從整個項目的入口進來之後,先流向我們的大組件vue,然後再流向其他子組件,看圖解:

二 v-model雙向數據綁定

  v-model的雙向數據綁定,v-model只能應用在input、textarea、select等標籤中,那v-model怎麼用呢,看程式碼,雙向數據綁定又是什麼意思呢,看下面的圖解。 

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <!--之前我們給input標籤加默認值是用的input標籤的value屬性,但是用vue的時候,vue會默認將這個value屬性忽略掉,也就是value={{ msg }}不生效,使用v-model來綁定數據-->      <!--<input type="text" value="">-->      <!-- v-model雙向數據綁定,打開頁面然後在input標籤中輸入內容,看效果 -->      <input type="text" v-model="msg">      <p>{{ msg }}</p>  </div>    <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el:'#app',          data(){              return{                  msg:'chao',              }          }        })    </script>  </body>  </html>

  效果圖:

  雙向數據綁定流程圖解:

  那麼我們自己通過前面學的內容來完成一個類似v-model的input標籤的一個雙向數據綁定的效果,這裡只是模擬了一個雙向數據綁定的效果,幫助大家理解其原理的大概實現方式,但實際其原理比下面的程式碼要複雜的多,注意這裡只是模擬,看程式碼: 

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <!-- 通過v-bind:value屬性,及input實時監聽輸入事件來完成一個雙向數據綁定的效果,textarearadio等可以這麼搞,但是他們綁定的change事件 -->      <input type="text" :value="msg" @input="valueHandler">      <p>{{ msg }}</p>  </div>    <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      //實際上的原理是通過一個叫做Object.defineProperty(監聽哪個對象,給什麼事件,回調函數,settergetter方法),比較複雜,用到了觀察者、監聽者、執行者等好多個對象來完成這個事情,了解一下就行了      let vm = new Vue({          el:'#app',          data(){              return{                  msg:'chao',              }          },          methods:{              valueHandler(e){                  //這就是setter方法,也就是賦值操作                  this.msg = e.target.value;              }          }        })    </script>  </body>  </html>

    模擬的就不用記了,咱們主要記住v-model的用法,實現雙向數據綁定。

  textarea的v-model

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <p style="white-space: pre-line;">{{ message }}</p>      <br>      <!--<textarea placeholder="內容">{{ message }}</textarea> 不能這樣寫-->      <textarea v-model="message" placeholder="內容"></textarea>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  message: 'chao',              }          }      })  </script>  </body>  </html>

   單個複選框的v-model:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <!--單選框v-model綁定了這個checked屬性,下面給了默認值為false,選中這個單選框,那麼checked屬性的值自動變為true-->      <input type="checkbox" id="checkbox" v-model="checked">      <label for="checkbox">{{ checked }}</label>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  // checked: '',//也可以給其他的默認值,但是選中值為true,取消選中值為false                  checked: false,              }          }      })  </script>  </body>  </html>

  多個複選框的v-model

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <div id='example-3'>          <!-- 注意,這裡選中之後,每個複選框的value屬性的值會添加到v-model綁定的後面這個 checkedNames數組中,如果沒有value屬性,那麼選中它時,添加的是null-->          <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">          <label for="jack">姓名Jack</label>          <input type="checkbox" id="john" value="John" v-model="checkedNames">          <label for="john">姓名John</label>          <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">          <label for="mike">姓名Mike</label>          <br>          <span>選擇的名稱: {{ checkedNames }}</span>      </div>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  checkedNames: []              }          }      })  </script>  </body>  </html>

  單選框raido的v-model

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <div id="example-4">          <!-- 選中之後picked的值為選中的單選框的value屬性的值,如果沒有這是value屬性,那麼選中值為空 -->        <input type="radio" id="one" value="One" v-model="picked">        <label for="one">1</label>        <br>        <input type="radio" id="two" value="Two" v-model="picked">        <label for="two">2</label>        <br>        <span>Picked: {{ picked }}</span>      </div>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  picked: '',              }          }      })  </script>  </body>  </html>

  單選下拉框的v-model

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <div id="example-5">          <!-- 單選下拉框,v-model寫在select標籤中,選中某個option標籤時,如果option標籤有value屬性,那麼v-model綁定的selected的值是value屬性對應的值,如果option標籤中沒有設置value屬性,那麼選中option標籤時,selected值為option標籤的文本內容 -->          <select v-model="selected">              <option disabled value="">請選擇</option>              <option value="xx1">A</option>              <option>B</option>              <option>C</option>          </select>          <span>Selected: {{ selected }}</span>      </div>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  selected: '',              }          }      })  </script>  </body>  </html>

    注意:如果 v-model 表達式的初始值未能匹配任何選項,<select> 元素將被渲染為「未選中」狀態。在 iOS 中,這會使用戶無法選擇第一個選項。因為這樣的情況下,iOS 不會觸發 change 事件。因此,更推薦像上面這樣提供一個值為空的禁用選項。

   多選下拉框的v-model

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">        <!-- 多選下拉框,v-model寫在select標籤中,選中某個option標籤時,如果option標籤有value屬性,那麼value屬性對應的值會添加到v-model綁定的selected數組中,如果option標籤中沒有設置value屬性,那麼選中option標籤時,option標籤的文本內容添加到v-model綁定的selected數組中 -->      <div id="example-6">          <select v-model="selected" multiple style="width: 50px;">              <option value="1">A</option>              <option>B</option>              <option>C</option>          </select>          <br>          <span>Selected: {{ selected }}</span>      </div>  </div>  <script src="vue.js"></script>  <script src="jquery.js"></script>  <script>      let vm = new Vue({          el: '#app',          data() {              return {                  // selected: '', //可以寫別的值,但是最終都會變為數組                  selected: [],              }          }      })  </script>  </body>  </html>

   值的綁定

    關於值的綁定大家看看下面的寫法就可以,這裡不多說了

    對於單選按鈕,複選框及選擇框的選項,v-model 綁定的值通常是靜態字元串 (對於複選框也可以是布爾值):

<!-- 當選中時,`picked` 為字元串 "a" -->  <input type="radio" v-model="picked" value="a">    <!-- `toggle` 為 true 或 false -->  <input type="checkbox" v-model="toggle">    <!-- 當選中第一個選項時,`selected` 為字元串 "abc" -->  <select v-model="selected">    <option value="abc">ABC</option>  </select>

    但是有時我們可能想把值綁定到 Vue 實例的一個動態屬性上,這時可以用 v-bind 實現,並且這個屬性的值可以不是字元串。

    複選框:

<input    type="checkbox"    v-model="toggle"    true-value="yes"    false-value="no"  >  // 當選中時 vm.toggle === 'yes'  // 當沒有選中時 vm.toggle === 'no'

      這裡的 true-value 和 false-value 特性並不會影響輸入控制項的 value 特性,因為瀏覽器在提交表單時並不會包含未被選中的複選框。如果要確保表單中這兩個值中的一個能夠被提交,(比如「yes」或「no」),請換用單選按鈕。

     單選按鈕:

<input type="radio" v-model="pick" v-bind:value="a">    // 當選中時  vm.pick === vm.a

     選擇框的選項

<select v-model="selected">      <!-- 內聯對象字面量 -->    <option v-bind:value="{ number: 123 }">123</option>  </select>    // 當選中時  typeof vm.selected // => 'object'  vm.selected.number // => 123

  修飾符

     .lazy  懶監聽

      在默認情況下,v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步 。你可以添加 lazy 修飾符,從而轉變為使用 change事件進行同步:

<!-- 在「change」時而非「input」時更新,意思就是輸入完按下回車鍵或者游標移走時才觸發數據的更新 -->  <input v-model.lazy="msg" >

    .number

       如果想自動將用戶的輸入值轉為數值類型,可以給 v-model 添加 number 修飾符,意思就是讓用戶只能輸入數字:

<input v-model.number="age" type="number">

      這通常很有用,因為即使在 type="number" 時,HTML 輸入元素的值也總會返回字元串。如果這個值無法被 parseFloat() 解析,則會返回原始的值。

    .trim

      如果要自動過濾用戶輸入的首尾空白字元,可以給 v-model 添加 trim 修飾符:

<input v-model.trim="msg">

  以後用vue開發的話,基本也就放棄jQuery了,因為jQuery裡面有的功能,vue裡面基本都有,vue沒有ajax,但是我們有別的辦法。

  另外給大家說一個vue社區,vue中文社區,這裡面有vue的很多項目,你可以來這裡找項目來學習,這裡的項目基本都只有前端的程式碼,後端需要我們自己寫,其中 vue awesome,是vue高星項目,也就是很多人都喜歡,比較nb的項目,記著FQ玩,不然有些東西你搜不了。

      這裡面有很多vue的高級應用,我們學的都是基礎,想玩高級的,就來這裡學。

   給大家推薦一些高星的vue-ui組件:後面我們的學習的項目,用Element UI。

    Vue 是一個輕巧、高性能、可組件化的MVVM庫,API簡潔明了,上手快。從Vue推出以來,得到眾多Web開發者的認可。在公司的Web前端項目開發中,多個項目採用基於Vue的UI組件框架開發,並投入正式使用。開發團隊在使用Vue.js框架和UI組件庫以後,開發效率大大提高,自己寫的程式碼也少了,很多介面效果組件已經封裝好了。在選擇Vue UI組件庫的過程中,通過GitHub上根據star數量、文檔豐富程度、更新的頻率以及維護等因素,也收集整理了一些優秀的Vue UI組件庫。下面介紹一下給大家強烈推薦優秀的的Vue UI組件庫。

1、 iView UI組件庫iView 是一套基於 Vue.js 的開源 UI 組件庫,主要服務於 PC 介面的中後台產品。iView的組件還是比較齊全的,更新也很快,文檔寫得很詳細。有公司團隊維護,比較可靠的Vue UI組件框架。iView生態也做得很好,還有開源了一個iView Admin,做後台非常方便。官網上介紹,iView已經應用在TalkingData、阿里巴巴、百度、騰訊、今日頭條、京東、滴滴出行、美團、新浪、聯想等大型公司的產品中。iView官網:https://www.iviewui.com/

2、Vux UI組件庫Vux是基於WeUI和Vue2.x開發的移動端UI組件庫,主要服務於微信頁面。Vux的定位已經很明確了,一是:Vue移動端UI組件庫,二是:WeUI的基礎樣式庫。Vux的組件涵蓋了所有的WeUI的內容,還擴展了一些常用的組件。比如:Sticky、timeline、v-chart、XCircle。Vux是個人維護的。但是GitHub上star還是很高的,達到13k。在GitHub上看到對issue的關閉還是很迅速的。Vux文檔基本的組件用法和效果都講解到位了。在vux官網上也展示了很多Vux的使用案例。在微信頁面開發中,基本沒有太多的bug,開發還是比較順手的。Vux官網:https://vux.li/

3、Element UI組件庫Element,一套為開發者、設計師和產品經理準備的基於 Vue 2.0 的桌面端組件庫。Element是餓了么前端開源維護的Vue UI組件庫,更新頻率還是很高的,基本一周到半個月都會發布一個新版本。組件齊全,基本涵蓋後台所需的所有組件,文檔講解詳細,例子也很豐富。沒有實際使用過,網上的Element教程和文章比較多。Element應該是一個品質比較高的Vue UI組件庫。Element官網:http://element.eleme.io/#/zh-CN

4、Mint UI組件庫Mint UI基於 Vue.js 的移動端組件庫,同樣出自餓了么前端的項目。Mint UI是真正意義上的按需載入組件。可以只載入聲明過的組件及其樣式文件。Mint UI 採用 CSS3 處理各種動效,避免瀏覽器進行不必要的重繪和重排,從而使用戶獲得流暢順滑的體驗。網上的影片教程很多都是基於Mint UI來講的,開發移動端web項目還是很方便,文檔也很簡介明了。很多頁面Mint UI組件都已經封裝好,基本可以照著例子寫,簡單的調整一下就可以實現。不過,在GitHub上看最後一次程式碼提交在2018年1月16日,截止到目前已經過去半年了。不知道是項目比較穩定沒有更新,還是項目有被廢棄的可能。我們會持續關注Mint UI的動態。Mint UI官網:http://mint-ui.github.io/#!/zh-cn

5、Bootstrap-Vue UI組件庫Bootstrap-VUE提供了基於vue2的Bootstrap V4組件和網格系統的實現,完成了廣泛和自動化的WAI ARA可訪問性標記。Bootstrap 4是最新發布的版本,與 Bootstrap3 相比擁有了更多的具體的類以及把一些有關的部分變成了相關的組件。同時 Bootstrap.min.css 的體積減少了40%以上。Bootstrap4 放棄了對 IE8 以及 iOS 6 的支援,現在僅僅支援 IE9 以上 以及 iOS 7 以上版本的瀏覽器。想當初剛流行響應式網站的時候,Bootstrap是世界上最受歡迎的建立移動優先網站的框架,Bootstrap可以說風靡全球。就算放在現在很多企業網站都是採用Bootstrap做的響應式。Bootstrap-Vue可以讓你在Vue中也實現Bootstrap的效果。Bootstrap-Vue官網:https://bootstrap-vue.js.org/

6、Ant Design Vue UI組件庫Ant Design Vue是 Ant Design 3.X 的 Vue 實現,開發和服務於企業級後台產品。在GitHub上可以找到幾個Ant Design的Vue組件。不過相比較而言,Ant Design Vue更勝一籌。Ant Design Vue共享Ant Design of React設計工具體系,實現了所有Ant Design of React的組件,支援現代瀏覽器和 IE9 及以上(需要 polyfills)。可以讓熟悉Ant Design的在使用Vue時,很容易的上手。Ant Design Vue官網:https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/

7、AT-UI UI組件庫AT-UI 是一款基於 Vue.js 2.0 的前端 UI 組件庫,主要用於快速開發 PC 網站中後台產品,支援現代瀏覽器和 IE9 及以上。AT-UI 更加精簡,實現了後台常用的組件。AT_UI官網:https://at-ui.github.io/at-ui/#/zh

8、Vant UI組件庫Vant是一個輕量、可靠的移動端 Vue 組件庫。Vant是有贊團隊開源的,主要維護也是有贊團隊。Vant Weapp 是有贊移動端組件庫 Vant 的小程式版本,兩者基於相同的視覺規範,提供一致的 API 介面,助力開發者快速搭建小程式應用。截止到目前,Vant已經開源了50+ 個經過有贊線上業務檢驗的組件。比如:、AddressEdit 地址編輯、AddressList 地址列表、Area 省市區選擇、Card 卡片、Contact 聯繫人、Coupon 優惠券、GoodsAction 商品頁行動點、SubmitBar 提交訂單欄、Sku 商品規格彈層。如果做商城的,不太在意介面,實現業務邏輯的話,用Vant組件庫開發還是很快的。Vant官網:https://youzan.github.io/vant/#/zh-CN/intro

9、cube-ui UI組件庫cube-ui 是基於 Vue.js 實現的精緻移動端組件庫。由滴滴內部組件庫精簡提煉而來,經歷了業務一年多的考驗,並且每個組件都有充分單元測試,為後續集成提供保障。在交互體驗方面追求極致。遵循統一的設計交互標準,高度還原設計效果;介面標準化,統一規範使用方式,開發更加簡單高效。支援按需引入和後編譯,輕量靈活;擴展性強,可以方便地基於現有組件實現二次開發。cube-ui官網:https://didi.github.io/cube-ui/#/zh-CN

10、Muse-UI UI組件庫Muse-UI基於 Vue 2.0 優雅的 Material Design UI 組件庫。Muse UI 擁有40多個UI 組件,用於適應不同業務環境。Muse UI 僅需少量程式碼即可完成主題樣式替換。Muse UI 可用於開發的複雜單頁應用Muse-UI官網:https://muse-ui.org/#/zh-CN

11、N3-components UI組件庫N3組件庫是基於Vue.js構建的,讓前端工程師和全棧工程師能快速構建頁面和應用。N3-components超過60個組件 組件列表、自定義樣式、支援多種模化範式(UMD)、使用ES6進行開發。N3官網:https://n3-components.github.io/N3-components/component.html

12、Mand MobileMand Mobile是面向金融場景的Vue移動端UI組件庫,豐富、靈活、實用,快速搭建優質的金融類產品,讓複雜的金融場景變簡單。Mand Mobile含有豐富的組件30+的基礎組件,覆蓋金融場景,極高的易用性組件均有詳細說明文檔、案例演示,汲取最前沿技術,組件化輕量化實現,兼顧穩定和品質,努力實現金融場景的全覆蓋。Mand Mobile官網:https://didi.github.io/mand-mobile/#/zh-CN/home

13、we-vue UI組件庫we-vue 是一套基於 Vue.js 的移動關組件庫,結合 weui.css 樣式庫,封裝了一系列組件,非常適於微信公眾號等移動端開發。we-vue 包含35+ 個組件,單元測試覆蓋率超 98%,支援 babel-plugin-import,完善的在線文檔,詳細的在線示例。we-vue官網:https://wevue.org/

14、veui UI組件庫veui是一個由百度EFE team開發的Vue企業級UI組件庫。目前文檔還沒有,只有demo。GitHub上說是正在進行的一項工作。那我們就耐心等待吧。veui官網:https://ecomfe.github.io/veui/components/#/

15、Semantic-UI-Vue UI組件庫Semantic-UI-Vue是基於 Vue.js對Semantic-UI 框架的實現。Semantic作為一款開發框架,幫助開發者使用對人類友好的HTML語言構建優雅的響應式布局。Semantic-UI-Vue提供了一個類似於 Semantic-UI 的 API 以及一組可訂製的主題。Semantic-UI-Vue官網:https://semantic-ui-vue.github.io/#/

16 vueAdmin 基於vuejs2和element的簡單的管理員模板

  以後我們做vue開發,基本都是基於組件開發的,下面我們就來學學組件基礎。

三 組件基礎

通常一個應用會以一棵嵌套的組件樹的形式來組織:

    每個組件都有自己的數據屬性、方法、監聽、鉤子函數等自己相應的功能,一個組件就可以稱為一個模組,組件化開發就是咱們說的模組化開發了。

下面我們來學一下組件怎麼玩。

1 局部組件 

   使用局部組件遵循三步:打油詩:聲子(聲明子組件)、掛子(掛在子組件)、用子(使用子組件)。

   再說局部組件之前,我先給大家說一個東西,叫做template模板,這個不是組件昂,只是我們後面組件要用這個東西,看程式碼

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>  <div id="app">      {{ msg }}  </div>  <div id="app2">    </div>    <script src="vue.js"></script>  <script>      //僅僅在實例化vue對象中如果既有el又有template屬性,並且template中定義模板的內容,那麼template模板的優先順序大於el      let vm = new Vue({          el:'#app',  //注意,這個id為app的標籤還必須在html中寫上,而且不寫的話會報錯          data(){              return{                  msg:'chao'              }          },          //template中的模板內容會將el指向的那個id為app的標籤給替換掉,替換成template裡面的模板內容,為什麼要寫這個東西呢,因為我們後面學習組件會用,至於做什麼用,大家往後面學          template:`  //用反引號的原因是裡面有寫標籤,屬性值用的雙引號              <div class="xxx">                  <h1>{{ msg }}</h1>              </div>          `      })    </script>  </body>  </html>

   看效果:這個回頭我們學到生命周期,你再回來看這個就會很清楚了。

  好,接下來學我們的局部組件,看程式碼:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">    </div>    <script src="vue.js"></script>  <script>      //整個這個vue對象可以理解為我們的根組件,大的root組件,裡面有其他幾個組件:比如說app組件(父組件)、header導航欄組件、aside側邊欄組件、content內容組件      //1 聲子,首先我們先聲明一個父組件,vue中的組件的名字首字母要大寫,為了跟標籤區分      let App = {  //是一個自定義對象,這個對象裡面除了el沒有,其他的Vue對象裡面的內容都有,並且組件中的data必須是個函數,一定要有返回值。          data(){ // 綁定當前app組件的數據屬性              return{                  text:'我是Jaden'              }          },          //子組件裡面加上template模板          template: //當前的模板裡面使用當前組件的數據屬性,和下面的Vue對象裡面的數據屬性沒關係昂              `                  <div id="dd1">                      <h2>{{ text }}</h2>                  </div>              `      };      let vm = new Vue({          el:'#app',          data(){              return{                  msg:'chao'              }          },          //template中的模板內容會將el指向的那個id為app的標籤給替換掉,替換成template裡面的模板內容,為什麼要寫這個東西呢,因為我們後面學習組件會用,至於做什麼用,大家往後面學          template:  //3 用子,template可以不用,如果不用那就是掛載到上面的el中去          `              <div class="xxx">                  <App /> //這樣寫,類似標籤的寫法,但是我們叫組件,還可以<App><App/>這樣寫,但是這樣寫的話,這個標籤後面的所有內容都不會顯示了,因為它封閉了,並且首字母都是要大寫的,為了和html中的標籤區分,並且要閉合標籤,就把App組件使用上了,將聲明的App組件裡面的內容全部掛載上了,注意,想要顯示內容,需要在我們上面聲明的App組件中寫template模板了,(拿我的程式碼測試的時候,別忘了把我注釋的這些內容刪除了,我寫在反引號裡面了)                  <a href="">aaa</a>              </div>          `,          //2 掛子          components:{ //組件們,可以在這裡掛載多個組件              // App:App  //寫法key:value,key是我們自己起的,value就是上面我們聲明的app組件名稱,並且如果key和value一樣,可以用下面的簡寫方式              App          }      })    </script>  </body>  </html>

  打開頁面看效果:

  看圖解:

  上面程式碼的另外一種寫法,不在vue對象裡面寫template了,並且除了App組件外,我們在給App組件加一個子組件,大家看程式碼,一個組件掛到另外一個組件上,那這個組件稱為子組件,另外一個組件稱為父組件。

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <!--也是兩種寫法,下面兩種都可以-->      <!--<App></App>-->      <App/>  </div>    <script src="vue.js"></script>  <script>      //除了下面的App組件外,我們再定義一個App組件的子組件,叫Vheader,別寫header,因為在H5中新出了個header標籤,以防有衝突      let Vheader = {          data() {              return {                }          },          //子組件裡面加上template模板,當然也可以不寫,但是一般都寫上,因為我們要通過它來定義內容,去替換我們掛載的組件內容,而且我們在組件裡面要寫很多的內容,還有一點大家要記著,不管是組件還是我們的vue對象裡面的template中寫標籤或者內容的時候,必須有個外層標籤包裹,這裡我們用的是div標籤,其他所有內容都寫在這個標籤裡面才行          // template: ` 這種寫法只能顯示第一個標籤的內容,另外一個標籤就報錯了,錯誤資訊是:Component template should contain exactly one root element. 意思是說必須有個根元素(根標籤)包裹,保證內容全部閉合,也就是下面的那種寫法。          //     <h2>chao</h2>          //     <h2>Jaden</h2>          // `          template: `              <div>                  <h2>chao</h2>                  <h2>Jaden</h2>              </div>          `      };          let App = {          data() {              return {                  text: '我是Jaden'              }          },          //子組件裡面加上template模板,當然也可以不寫,但是一般都寫上,因為我們要通過它來定義內容,去替換我們掛載的組件內容,而且我們在組件裡面要寫很多的內容          template: //現在我們將子組件Vheader在App組件的template中使用一下,              `                  <div id="dd1">                      <h2>{{ text }}</h2>                      <Vheader></Vheader>                  </div>              `          ,          components:{              Vheader,  //將子組件掛載到App組件的裡面,別忘了,除了el屬性,vue對象裡面的所有屬性或者方法在組件中都有          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          //template中的模板內容會將el指向的那個id為app的標籤給替換掉,替換成template裡面的模板內容,為什麼要寫這個東西呢,因為我們後面學習組件會用,至於做什麼用,大家往後面學          //此時我就把template去掉了,那麼將App組件寫到了上面id為app的div標籤中,大家看看,說了,不寫template,那麼就會掛載到el對應的那個標籤中          //2 掛子          components: {              App          }      })      //現在我們寫的組件都放到這一個文件裡面了,比較亂是不是,將來我們是模組化開發的,這些組件都會分文件來存寫的,然後以import的形式引入,然後再掛載,再使用,現在先忍著吧,哈哈  </script>  </body>  </html>

    上面程式碼的簡單流程圖解:

 簡單總結一下

  1.聲明子   

let App = {          data() {              return {                  text: '我是Jaden'              }          },            template:              `                  <div id="dd1">                    </div>              `          ,      };

   2.掛子

{          如果有template,用template也是可以掛子的,並且template優先順序比el高          template:`<App />`          components: {              App //子組件          }  }

     3 用子 

父組件的template中,或者el對應的標籤中來使用  <App></App>  <App/>  在template中使用的時候可以這樣寫  template:`  <div>      <App />  </div>  `,  或者直接寫  template:`<App />`,

    上面我們學了一下組件的基礎,我們提到了一個模組化開發,有些朋友可能不太理解,那麼我們在GitHub上下載一個項目,來看看:

    第一步:到GitHub上下載這個項目

    下載到本地之後,按照人家的說明來運行項目

# 克隆到本地,或者下載zip壓縮包  git clone https://github.com/bailicangdu/vue2-happyfri-master.git    # 進入文件夾  cd vue2-happyfri-master    # 安裝依賴  npm install 或 yarn(推薦)    # 開啟本地伺服器localhost:8088  npm run dev    # 發布環境  npm run build

     一個組件裡面包含了HTML、CSS、JS等內容,我們就看一下這個項目的src文件夾裡面的main.js和page文件夾裡面的內容,大致看看就清晰一些了。

  2 全局組件

  直接看程式碼,局部組件使用時需要掛載,全局組件使用時不需要掛載。那麼他們兩個什麼時候用呢,局部組件就在某個局部使用的時候,全局組件是大家公用的,或者說每個頁面都有這麼一個功能的時候,在哪裡可能都會用到的時候。

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <App/>  </div>    <script src="vue.js"></script>  <script>        // 全局組件,Vue.component(參數1,參數2),第一個參數是起的全局組件的名字,第二個參數是組件的options,這個組件是全局的,在任意組件中都可以用,使用的時候不需要掛載了,局部組件才需要掛載      //下面的操作,我們將VBtn這個全局組件用到了App組件和Vheader組件中,那麼這個VBtn組件稱為App組件和Vheader組件的子組件      Vue.component('VBtn',{         data(){             return{                  btnName:'按鈕',             }         },         // template:``         template:`<button>{{ btnName }}</button>`      });        //下面是聲明局部組件      let Vheader = {          data() {              return {                  message:'chao'              }          },          //使用全局組件          template: `              <div>                  <h2>{{ message }}</h2>                  <h2>Jaden</h2>                  <VBtn></VBtn>              </div>          `      };      let App = {          data() {              return {                  text: '我是Jaden'              }          },          //使用全局組件          template:              `                  <div id="dd1">                      <h2>{{ text }}</h2>                      <Vheader></Vheader>                      <VBtn></VBtn>                  </div>              `          ,          components:{              Vheader,          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          components: {              App          }      })  </script>  </body>  </html>

  我們發現這個全局組件應用到哪個組件上都可以,就比如這個button組件一樣,我們可能需要很多的button按鈕,每個button按鈕裡面的文字還不一樣,這樣我們就需要按照自己組件中需求來改button按鈕裡面的文字,這個怎麼玩呢,看程式碼:slot(插槽)內容分發組件

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <App/>  </div>    <script src="vue.js"></script>  <script>        Vue.component('VBtn',{         data(){             return{                  btnName:'按鈕',             }         },         // template:``         // template:`<button>{{ btnName }}</button>`         //button按鈕中寫slot組件<slot>{{ btnName }}</slot> ,那麼下面其他組件中使用這個全局組件的時候,就可以動態的更改button按鈕的文字了,寫法<VBtn>刪除</VBtn>,那麼刪除兩個字就替換了按鈕兩個字         template:`<button>                      <slot>{{ btnName }}</slot>                  </button>`      });        let Vheader = {          data() {              return {                  message:'chao'              }          },          template: `              <div>                  <h2>{{ message }}</h2>                  <h2>Jaden</h2>                  <VBtn>編輯</VBtn>              </div>          `      };      let App = {          data() {              return {                  text: '我是Jaden'              }          },          //注意<VBtn>你好</VBtn>,這樣寫直接來改button的文字是不行的,我們需要將文字'你好',映射給上面我們定義全局組件時的template中的button按鈕中的文字,這時候我們就需要使用Vue內置的slot組件,叫做內容分發組件,看寫法          template:              `                  <div id="dd1">                      <h2>{{ text }}</h2>                      <Vheader></Vheader>                      <VBtn>刪除</VBtn>                      <VBtn></VBtn>                  </div>              `          ,          components:{              Vheader,          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          components: {              App          }      })  </script>  </body>  </html>

四 父子組件傳值

通過prop屬性進行傳值

1 首先說父組件往子組件傳值  :兩步

  1.在子組件中使用props屬性聲明,然後可以直接在子組件中任意使用

  2.父組件要定義自定義的屬性

  看程式碼:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <App/>  </div>    <script src="vue.js"></script>  <script>        let Vheader = {          data() {              return {                  message:'chao'              }          },          //掛載父組件的屬性,此時在子組件的任意位置就可以使用這個父組件的text對應的數據了,但是需要父組件將值傳給子組件          props:['msg','msg2','msg3','msg4','msg5'],          template: `              <div class="c1">                  <h2>{{ message }}</h2>                  <h2>Jaden</h2>                  <h3>{{ msg }}</h3>                  <h3>{{ msg2 }}</h3>                  <h3>{{ msg3.id }}</h3>                  <h3>{{ msg3.name }}</h3>                  <h3>{{ msg4 }}</h3>                  <h3>{{ msg5 }}</h3>              </div>          `      };      let App = {          data() {              return {                  text: '我是父組件的數據1',//字元串                  text2: 22,  //數字                  text3: true,  //布爾值                  post:{  //自定義對象                      id:1,                      name:'jj'                  },                  l1:[11,22,33],  //數組              }          },          //<Vheader :msg="text"></Vheader>這就是將父組件的text屬性的值,給了Vheader標籤的msg屬性,這個msg屬性就是上面子組件的props裡面的msg,props['msg'],如果想綁定多個值呢?可以搞一個自定義對象(其實可以傳列表什麼的其他數據),存放所有的數據,但是<Vheader :msg="text" :msg2="text2" v-bind="post"></Vheader>這樣的寫法是將post這個自定義對象裡面的鍵值對作為屬性放到了上面子組件的class='c1'的div標籤裡面,作為了這個div標籤的屬性了,並不是我們想要的,我們想要的是在div標籤裡面的h標籤裡面用這些數據作為文本內容,所以我們的寫法應該是這樣的<Vheader :msg="text" :msg2="text2" v-bind:msg3="post"></Vheader>,不然我們在子組件的div標籤裡面這樣<h3>{{ msg3.id }}</h3>使用的時候就會報錯,所以注意寫法,並且可以簡寫<Vheader :msg="text" :msg2="text2" :msg3="post"></Vheader>          template:              `                  <div id="dd1">                      <h1>{{ text }}</h1>                      <Vheader :msg="text" :msg2="text2" :msg3="post" :msg4="l1" :msg5="text3"></Vheader>                    </div>              `          ,          components:{              Vheader,          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          components: {              App          }      })  </script>  </body>  </html>

   子組件還可以給子組件的子組件傳值,將父組件的值傳遞給孫子組件的意思,看程式碼:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <App/>  </div>    <script src="vue.js"></script>  <script>        Vue.component('VBtn',{         data(){             return{               }         } ,         template:`              <button>                 {{ id }}              </button>         `,          props:['id']  //孫子組件使用父組件的數據      });      let Vheader = {          data() {              return {                  message:'chao'              }          },          props:['msg','msg2','msg3','msg4','msg5'],          template: `              <div class="c1">                  <h2>{{ message }}</h2>                  <h2>Jaden</h2>                  <h3>{{ msg }}</h3>                  <h3>{{ msg2 }}</h3>                  <h3>{{ msg3.id }}</h3>                  <h3>{{ msg3.name }}</h3>                  <h3>{{ msg4 }}</h3>                  <h3>{{ msg5 }}</h3>                  <br>                  //看寫法                  <!--<VBtn :id="msg"></VBtn>-->                  <VBtn :id="msg3.id"></VBtn>              </div>          `      };      let App = {          data() {              return {                  text: '我是父組件的數據1',//字元串                  text2: 22,  //數字                  text3: true,  //布爾值                  post:{  //自定義對象                      id:1,                      name:'jj'                  },                  l1:[11,22,33],  //數組              }          },          template:              `                  <div id="dd1">                      <h1>{{ text }}</h1>                      <Vheader :msg="text" :msg2="text2" :msg3="post" :msg4="l1" :msg5="text3"></Vheader>                    </div>              `          ,          components:{              Vheader,          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          components: {              App          }      })  </script>  </body>  </html>

  2 子組件父組件傳值  :兩步

  a.子組件中使用this.$emit('fatherHandler',val);fatherHandler是父組件中使用子組件的地方添加的綁定自定義事件<Vheader  @fatherHandler="appFatherHandler"></Vheader> 

  b.父組件中的methods中寫一個自定義的事件函數:appFatherHandler(val){},在函數裡面使用這個val,這個val就是上面子組件傳過來的數據

   看程式碼:

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>    <div id="app">      <App/>  </div>    <script src="vue.js"></script>  <script>      //通過點擊,將孫子組件的button中的id值改掉,然後父組件和爺爺組件的id數據值都跟著改,這時候比較複雜,需要一個自定義事件,並且記住每個組件的事件函數中的this,都是當前事件調用者的組件,前提是你用的普通函數來寫的事件執行函數,從孫子組件傳遞給爺爺組件的傳遞順序是這樣的  孫子-->父親-->爺爺      Vue.component('VBtn',{         data(){             return{               }         } ,           template:`              <button @click="clickHandler">                 {{ id }}              </button>         `,          props:['id'], //別忘了我說的,這個東西只要一聲明,這裡面的數據在哪裡都可以用,相當於在上面的data(){return{id:}}方法裡面添加了這個數據屬性          methods:{             clickHandler(){                 //這個clickHandler事件函數是個普通函數,那麼這個this就是事件的調用者,就是我們的VBtn組件                 console.log('4444',this);//_uid: 3                 //VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}                 // 你需要使用this的$emit方法,vue提供的方法, this.$emit('父組件中聲明的自定義事件','傳的值'),點擊事件傳值,此時我們現在組件的父組件是下面的Vheader組件,this.$emit('vheaderClick')的意思就是觸發父組件的這個自定義的vheaderClick事件                 //  this.$emit('vheaderClick');                 //那麼我就可以通過this.id++來將id值改變,並且傳遞給父組件                 this.id++;                 this.$emit('vheaderClick',this.id); //將this.id的值傳遞給了父組件的vheaderClick事件,所以下面的事件需要寫個形參來接收這個數據                  //然後往Vheader的父組件app傳值,將孫子組件的值傳遞給爺爺組件的意思               }          }      });      let Vheader = {          data() {              return {                  message:'chao'              }          },          created(){              console.log('@@@@',this)//_uid: 2,              //VueComponent {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}          },            props:['msg','msg2','msg3','msg4','msg5'],          //我們想把孫子組件的數據先傳遞給父組件Vheader,然後寫法是:Vheader組件中使用上面子組件的地方(標籤)添加一個綁定事件,這個綁定的事件的值要等於上面我們子組件中的methods裡面的事件名稱相同,注意下面我們要在使用子組件的地方寫一個自定義事件了,這個自定義事件的名稱不能和js原生事件的名稱衝突(clickinput等等)          template: `              <div class="c1">                  <h1>我是Vheader組件</h1>                  <h2>{{ message }}</h2>                  <h2>Jaden</h2>                  <h3>{{ msg }}</h3>                  <h3>{{ msg2 }}</h3>                  <h3>{{ msg3.id }}</h3>                    <VBtn :id="msg3.id" @vheaderClick="vheaderClickHandler"></VBtn>              </div>          `,          //需要寫methods來寫我們在template中使用子組件的地方綁定的事件          methods:{              vheaderClickHandler(val){                  // alert(1);                  alert(val);                  this.$emit('fatherHandler',val);                }          },      };      let App = {          data() {              return {                  text: '我是父組件的數據1',//字元串                  text2: 22,  //數字                  text3: true,  //布爾值                  post:{  //自定義對象                      id:1,                      name:'jj'                  },                  l1:[11,22,33],  //數組              }          },            created(){              console.log('!!!!',this)//_uid: 1              //VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}          },          methods:{            appFatherHandler(val){                // alert('app組件的id',val);                this.post.id=val;//將app裡面的id改掉,那麼下面使用了post.id的值就變了            }          },          template:              `                  <div id="dd1">                      <h1>{{ text }}</h1>                      <h1>我是父組件的id值:{{ post.id }}</h1>                      <Vheader :msg="text" :msg2="text2" :msg3="post" :msg4="l1" :msg5="text3" @fatherHandler="appFatherHandler"></Vheader>                    </div>              `          ,          components:{              Vheader,          }      };      let vm = new Vue({          el: '#app',          data() {              return {                  msg: 'chao'              }          },          created(){              console.log('>>>>',this) //_uid:0              //Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}          },          components: {              App          }      })  </script>  </body>  </html>

五 平行組件傳值

 先看一下什麼是平行組件,看圖:

  平行組件的傳值,假如說我們將組件1的數據傳遞給組件2,那麼就需要在組件2中聲明一個方法,通過$on來聲明,而組件1中要觸發一個方法,通過$emit來觸發。並且前提是這兩個方法要掛載到一個公用的方法上,比較懵逼是不是,你想,在組件1中聲明的方法,在組件2中能用嗎,是不是不能用啊,所以我們需要一個公用的方法,兩個組件將$on和$emit都放到這個公用的方法上,而不是綁定給某個組件的this對象上,說了半天都是廢話,直接看程式碼吧:   

<!doctype html>  <html lang="en">  <head>      <meta charset="UTF-8">      <meta name="viewport"            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">      <meta http-equiv="X-UA-Compatible" content="ie=edge">      <title>Document</title>  </head>  <body>    <div class="app">      <App />    </div>    <script src="vue.js"></script>  <script>      //第二步:做一個全局的vue對象,這個對象來調用$on和$emit方法,注意:這個vue對象和下面的那個vue對象不是一個對象昂,兩個的記憶體地址是不同的,你現在相當於實例化了兩個vue對象,但是這個vue對象只是單純的作為平行組件傳值的一個公交車      let bus = new Vue();          //下面的組件,我們通過平行組件傳值的方式來搞,下面寫了兩個全局組件來演示平行組件Test和Test2,我想將Test組件中的數據傳遞給Test2,Test-->Test2,那麼Test2中要通過$on來聲明事件$on('事件的名字',function(val){}),Test組件中要觸發事件$emit('Test組件中聲明的事件',值),前提是,這兩個方法$on和$emit必須綁定在同一個實例化對象中,一般稱這個實例化對象為bus對象,公交車對象      Vue.component('Test2',{         data(){             return{                 msg:'Test2數據',                 text:'',             }         } ,          //使用一下Test組件傳遞過來的數據          template:`             <h1>{{ text }}</h1>          `,          methods:{             clickHandler(){               }          },          //可以在created方法中接收Test組件傳過來的數據          created(){             //聲明事件,現在並沒有調用,只有下面的那個Test組件裡面的按鈕點擊事件觸發才會調用這個事件             // this.$on('TestData',function (val) { 通過this綁定是不行的,兩個組件之間沒有關係             // bus.$on('TestData',function (val) {             //      alert(val);             //      this.text = val; //現在想給Test2組件裡面的text數據屬性傳值,直接這樣寫是不行的因為this現在指向的是bus那個vue對象,所以this的指向需要變化,所以我們需要用箭頭函數來改變this的指向             // })              bus.$on('TestData', (val) => {                  alert(val);                  this.text = val; //this現在只的是bus那個vue對象,所以this的指向需要變化,所以我們需要用箭頭函數來改變this的指向             })          }      });      Vue.component('Test',{         data(){             return{                 msg:'我是子組件Test的數據',               }         } ,          props:['txt'],//下面<Test txt="chao"></Test>這種寫法的靜態傳值          //通過點擊這個按鈕,把子組件的數據傳遞給下面的Vheader組件          template:`              <!--<button @click="clickHandler">{{ txt }}</button>-->              <button @click="clickHandler">{{ txt }}</button>          `,          methods:{             clickHandler(){                  // this.$emit('TestData',this.msg);通過this綁定是不行的,兩個組件之間沒有關係                  bus.$emit('TestData',this.msg)             }          },        });        let Vheader = {          data(){              return{                  txt:'Jaden', //動態的給下面的Test組件傳值,注意<Test txt="chao"></Test>txt前面沒有:的是靜態傳值的方式              }          },          template:`              <div class="header">                  <!--<Test txt="chao"></Test>-->                  <Test :txt="txt"></Test>                    <!--<Test></Test>-->                  <Test2></Test2>                </div>          `      };        let App={          data(){              return{                }          },          template:`              <div class="xxx">                  <Vheader></Vheader>                </div>            `,          components:{              Vheader          }      };      new Vue({          el:'.app',          data(){              return{                }          },          //掛載          components:{              App          }        })      </script>    </body>  </html>

  說了半天的父子組件傳值,你應該可以想到,通過平行組件傳值的方法其實都可以解決,做一個全局的對象bus來做組件之間的傳值。但是我們後面要學的vuex更好用,前面這個bus用的也挺多的,這個vuex就像一個前端的資料庫,把前端的數據都保存在vuex裡面了,那麼所有的組件都可以用這裡面的數據,簡單在這裡提一下吧:看圖:

     就大概這麼個意思吧,後面我們會學到昂,目前我們學了兩種組件之間數據傳值的方案,其實有7種,其他的沒必要學了昂,玩好這兩個就夠你用了。

六 xxx

七 xxx

八 xxx