1. 程式人生 > 實用技巧 >雜湊表結構_雜湊表的實現

雜湊表結構_雜湊表的實現

本節目錄

一 什麼是元件

  首先給大家介紹一下元件(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實時監聽輸入事件來完成一個雙向資料繫結的效果,textarea\radio等可以這麼搞,但是他們繫結的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(監聽哪個物件,給什麼事件,回撥函式,setter\getter方法),比較複雜,用到了觀察者、監聽者、執行者等好多個物件來完成這個事情,瞭解一下就行了
    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-valuefalse-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-UIUI元件庫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-uiUI元件庫cube-ui 是基於 Vue.js 實現的精緻移動端元件庫。由滴滴內部元件庫精簡提煉而來,經歷了業務一年多的考驗,並且每個元件都有充分單元測試,為後續整合提供保障。在互動體驗方面追求極致。遵循統一的設計互動標準,高度還原設計效果;介面標準化,統一規範使用方式,開發更加簡單高效。支援按需引入和後編譯,輕量靈活;擴充套件性強,可以方便地基於現有元件實現二次開發。cube-ui官網:https://didi.github.io/cube-ui/#/zh-CN

    10、Muse-UIUI元件庫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-componentsUI元件庫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-vueUI元件庫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-VueUI元件庫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>