本節目錄css
首先給你們介紹一下組件(component)的概念html
咱們在進行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開發的:vue
每一個組件中都有對應的data(),methods,watch等屬性功能,組件是爲了功能模塊化,爲了解耦,每一個組件有本身的數據屬性,監聽本身的數據屬性等操做。jquery
後面咱們學習組件會知道組件是能夠嵌套的,那麼就看看圖解組件嵌套的組件樹,及數據流向,數據是單項數據流 ,數據從整個項目的入口進來以後,先流向咱們的大組件vue,而後再流向其餘子組件,看圖解:git
v-model的雙向數據綁定,v-model只能應用在input、textarea、select等標籤中,那v-model怎麼用呢,看代碼,雙向數據綁定又是什麼意思呢,看下面的圖解。 github
<!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>
效果圖:web
雙向數據綁定流程圖解:ajax
那麼咱們本身經過前面學的內容來完成一個相似v-model的input標籤的一個雙向數據綁定的效果,這裏只是模擬了一個雙向數據綁定的效果,幫助你們理解其原理的大概實現方式,但實際其原理比下面的代碼要複雜的多,注意這裏只是模擬,看代碼: vuex
<!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-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組件庫。
一、 iView UI組件庫iView 是一套基於 Vue.js 的開源 UI 組件庫,主要服務於 PC 界面的中後臺產品。iView的組件仍是比較齊全的,更新也很快,文檔寫得很詳細。有公司團隊維護,比較可靠的Vue UI組件框架。iView生態也作得很好,還有開源了一個iView Admin,作後臺很是方便。官網上介紹,iView已經應用在TalkingData、阿里巴巴、百度、騰訊、今日頭條、京東、滴滴出行、美團、新浪、聯想等大型公司的產品中。iView官網:https://www.iviewui.com/
二、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/
三、Element UI組件庫Element,一套爲開發者、設計師和產品經理準備的基於 Vue 2.0 的桌面端組件庫。Element是餓了麼前端開源維護的Vue UI組件庫,更新頻率仍是很高的,基本一週到半個月都會發佈一個新版本。組件齊全,基本涵蓋後臺所需的全部組件,文檔講解詳細,例子也很豐富。沒有實際使用過,網上的Element教程和文章比較多。Element應該是一個質量比較高的Vue UI組件庫。Element官網:http://element.eleme.io/#/zh-CN
四、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
五、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/
六、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/
七、AT-UI UI組件庫AT-UI 是一款基於 Vue.js 2.0 的前端 UI 組件庫,主要用於快速開發 PC 網站中後臺產品,支持現代瀏覽器和 IE9 及以上。AT-UI 更加精簡,實現了後臺經常使用的組件。AT_UI官網:https://at-ui.github.io/at-ui/#/zh
八、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
九、cube-ui UI組件庫cube-ui 是基於 Vue.js 實現的精緻移動端組件庫。由滴滴內部組件庫精簡提煉而來,經歷了業務一年多的考驗,而且每一個組件都有充分單元測試,爲後續集成提供保障。在交互體驗方面追求極致。遵循統一的設計交互標準,高度還原設計效果;接口標準化,統一規範使用方式,開發更加簡單高效。支持按需引入和後編譯,輕量靈活;擴展性強,能夠方便地基於現有組件實現二次開發。cube-ui官網:https://didi.github.io/cube-ui/#/zh-CN
十、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
十一、N3-components UI組件庫N3組件庫是基於Vue.js構建的,讓前端工程師和全棧工程師能快速構建頁面和應用。N3-components超過60個組件 組件列表、自定義樣式、支持多種模化範式(UMD)、使用ES6進行開發。N3官網:https://n3-components.github.io/N3-components/component.html
十二、Mand MobileMand Mobile是面向金融場景的Vue移動端UI組件庫,豐富、靈活、實用,快速搭建優質的金融類產品,讓複雜的金融場景變簡單。Mand Mobile含有豐富的組件30+的基礎組件,覆蓋金融場景,極高的易用性組件均有詳細說明文檔、案例演示,汲取最前沿技術,組件化輕量化實現,兼顧穩定和品質,努力實現金融場景的全覆蓋。Mand Mobile官網:https://didi.github.io/mand-mobile/#/zh-CN/home
1三、we-vue UI組件庫we-vue 是一套基於 Vue.js 的移動關組件庫,結合 weui.css 樣式庫,封裝了一系列組件,很是適於微信公衆號等移動端開發。we-vue 包含35+ 個組件,單元測試覆蓋率超 98%,支持 babel-plugin-import,完善的在線文檔,詳細的在線示例。we-vue官網:https://wevue.org/
1四、veui UI組件庫veui是一個由百度EFE team開發的Vue企業級UI組件庫。目前文檔尚未,只有demo。GitHub上說是正在進行的一項工做。那咱們就耐心等待吧。veui官網:https://ecomfe.github.io/veui/components/#/
1五、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種,其餘的不必學了昂,玩好這兩個就夠你用了。