前面學習了vue的基礎指令,瞭解了相關的鉤子函數,這一章學習vue的組件,組件 (Component) 是 Vue.js 最強大的功能之一,組件能夠擴展 HTML 元素,封裝可重用的代碼,組件系統讓咱們能夠用獨立可複用的小組件來構建大型應用,幾乎任意類型的應用的界面均可以抽象爲一個組件樹:javascript
菜鳥教程地址:https://www.runoob.com/vue2/vue-tutorial.htmlcss
官網學習地址:https://cn.vuejs.org/html
入門學習更加推薦菜鳥vue
<body> <!-- 建立兩個承載容器 --> <div id="app"> <my-fristcomponent></my-fristcomponent> </div> <div id="app1"> <!-- 在視圖層 直接寫組件的標籤名就能夠調用全局組件 --> <my-fristcomponent></my-fristcomponent> </div> <!-- 值得注意的點是 在js中定義了Vue全局組件在視圖層中咱們的全局組件必須在建立實例的塊中使用 --> <!-- 以下,app2咱們沒有綁定vue實例因此組件不會生效--> <div id="app2"> <my-fristcomponent></my-fristcomponent> </div> <my-fristcomponent></my-fristcomponent> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> /* 自定義全局組件 my-fristcomponent是自定義組件的標籤名 template是模板的意思,後面寫組件的內容 */ Vue.component('my-fristcomponent', { template: "<p>個人第一個組件</p>" }); /* 建立 兩個vue實例 */ new Vue({ el: "#app" }); new Vue({ el: "#app1" }) </script> </body>
<body> <div id="app"> <!-- 在使用組件,若是使用駝峯命名,vue會自動解析,咱們 調用時須要用-隔開並使用小寫,以下兩種方式是能夠 --> <Hello-world></Hello-world> <hello-world></hello-world> <!-- 錯誤 --> <HelloWorld></HelloWorld> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> /* 在建立實例時,咱們遵循駝峯命名法 */ Vue.component('HelloWorld', { template: "<p>HelloWorld</p>" }) new Vue({ el: "#app", }) </script> </body>
<body> <div id="app"> <data-component></data-component> <button @click="change">改變</button> {{msg}} </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component("dataComponent", { /* 在定義組件時也能夠寫data,可是data裏面必須是一個函數 且這個函數必須有返回值 */ data: function() { return { msg: "data返回值" } }, // 組件中的msg 只能夠在該模板中使用 template: '<p >{{msg}}</p>' }) new Vue({ el: "#app", data: { msg: "121" }, methods: { // 定義change返回沒法改變組件中的 change: function() { // alert(11); this.msg = "1212"; } } }) </script> </body>
前面已經寫個全局指令,全局過濾器,局部過濾器之類的,因此局部組件與全局組件的區別是同樣的,局部組件只能在當前實例才能使用java
<body> <div id="app"> <my-component></my-component> </div> <div id="app1"> // my-component組件註冊不正確 局部組件不能在其餘實例中使用 <my-component></my-component> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var vm = new Vue({ el: "#app", /* data: { msg: "局部指令", }, */ components:{ 'my-component':{ data:function(){ return{ msg:"局部指令" } }, template:"<p>{{msg}}</p>" } } }); new Vue({ el:"#app1" }) </script> </body>
注意:組件模板中的內容只容許存在一個根標籤,多了的話只會解析第一個git
// 下面模板定義了兩個p標籤,至關於兩個根標籤,那麼第二個就不會生效 template: '<p >{{msg}}</p> <p>{{msg}}</p>
<body> <div id="app"> <p>實例中定義的屬性內容是: {{pmsg}}</p> #### 下面是組件 <!-- :content 等同於v-bind:content 瀏覽器打印結果: 我是定義的組件內容 我是標題 父組件內容 --> <!-- 組件定義的模板中使用的值帶有props的屬性,在視圖層使用v-bind綁定 父組件的數據從而造成賦值,也能夠不綁定直接賦值 eg:<menu-item title="我自動賦值" content="我自動賦值內容"></menu-item> --> <menu-item v-bind:title="ptitle" :content="pmsg"></menu-item> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // menu-item 定義全局組件 Vue.component('menu-item', { // 組件 用props 屬性來接受父組件傳遞的參數 props: ['title', 'content'], //組件中 的data必須是函數,且有返回值 data: function() { return { msg: "我是定義的組件內容", title: "我是定義的組件的標題" } }, // 定義組件模版 template: '<p><span>{{msg}}</span><br><span>{{title}}</span><br><span>{{content}}</span></p>' }); new Vue({ el: "#app", data: { pmsg: "父組件內容", ptitle: "我是標題" } }); </script> </body>
$emit()
觸發事件$emit()
第一個參數爲 自定義的事件名稱 第二個參數爲須要傳遞的數據<body> <div id="app"> <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div> <!-- 2 父組件用v-on 監聽子組件的事件 這裏 enlarge-text 是從 $emit 中的第一個參數對應 handle 爲對應的事件處理函數 --> <menu-item :parr='parr' @enlarge-text='handle($event)' @shrink-text='shrink($event)' @gain-num="gainNume($event)" ></menu-item> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> /* 子組件向父組件傳值-攜帶參數 */ Vue.component('menu-item', { props: ['parr'], /* data: function() { return { num: 0, } }, */ template: ` <div> <ul> <li :key='index' v-for='(item,index) in parr'>{{item}}</li> </ul> ### 一、子組件用$emit()觸發事件 ### 第一個參數爲 自定義的事件名稱 第二個參數爲須要傳遞的數據 <br> <button @click='$emit("gain-num", 0)'>將子組件的值傳遞到父組件</button> <button @click='$emit("enlarge-text", 5)'>擴大父組件中字體大小</button> <button @click='$emit("shrink-text", 5)'>縮小父組件中字體大小</button> </div> ` }); var vm = new Vue({ el: '#app', data: { pmsg: '父組件中內容', parr: ['apple', 'orange', 'banana'], fontSize: 10 }, methods: { handle: function(val) { alert(val) // 擴大字體大小 this.fontSize += val; }, shrink: function(val) { // 縮小 字體大小 this.fontSize -= val; }, gainNume: function(val){ alert(val); } } }); </script> </body>
簡單想象一下兄弟組件,在全局組件中,定義兩個全局組件那麼這兩個組件就是兄弟組件,局部組件也是同樣的,在當個實例中可定義多個局部組件組件之間就是兄弟關係瀏覽器
<body> <div id="app"> <div>父組件</div> <div> <button @click='handle'>銷燬事件</button> </div> <test-tom></test-tom> <test-jerry></test-jerry> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> /* 兄弟組件之間數據傳遞 */ //一、 提供事件中心 var hub = new Vue(); Vue.component('test-tom', { data: function() { return { num: 0 } }, template: ` <div> <div>TOM:{{num}}</div> <div> <button @click='handle'>點擊</button> </div> </div> `, methods: { handle: function() { //二、傳遞數據方,經過一個事件觸發hub.$emit(方法名,傳遞的數據) 觸發兄弟組件的事件 hub.$emit('jerry-event', 2); } }, mounted: function() { // 三、接收數據方,經過mounted(){} 鉤子中 觸發hub.$on(方法名 hub.$on('tom-event', (val) => { this.num += val; }); } }); Vue.component('test-jerry', { data: function() { return { num: 0 } }, template: ` <div> <div>JERRY:{{num}}</div> <div> <button @click='handle'>點擊</button> </div> </div> `, methods: { handle: function() { //二、傳遞數據方,經過一個事件觸發hub.$emit(方法名,傳遞的數據) 觸發兄弟組件的事件 hub.$emit('tom-event', 1); } }, mounted: function() { // 三、接收數據方,經過mounted(){} 鉤子中 觸發hub.$on()方法名 hub.$on('jerry-event', (val) => { this.num += val; }); } }); var vm = new Vue({ el: '#app', data: { }, methods: { handle: function() { //四、銷燬事件 經過hub.$off()方法名銷燬以後沒法進行傳遞數據 hub.$off('tom-event'); hub.$off('jerry-event'); } } }); </script> </body>
<body> <div id="app"> <alert-box></alert-box> <!-- 插槽至關於一個默認的佔位符,若是沒有去修飾值修飾它,它會以默認值展示 --> <alert-box1>{{msg}}</alert-box1> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component("alert-box", { template: ` <div> ###在組件模板中定一個插槽<br> <slot>我是一個插槽</slot> </div> ` }) Vue.component("alert-box1", { template: ` <div> ###雖然我也是一個插槽可是我被佔用了<br> <slot>我是一個插槽</slot> </div> ` }) new Vue({ el: "#app", data: { msg:"我要佔用插槽" } }); </script> </body>
<body> <div id="app"> <table-list> <!-- 在模板內分別爲兩個插槽填充數據 達到表格效果 --> <template slot='heands'> <th>ID</th> <th>名稱</th> </template> <template slot='tablebody'> <tr v-for="l in list"> <td>{{l.id}}</td> <td>{{l.name}}</td> </tr> </template> </table-list> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // 定義一個 table 組件 Vue.component('table-list', { // 定義一個模板,定義兩個插槽heands 和 tablebody template: ` <table> <tr> <slot name='heands'></slot> </tr> <tbody> <slot name="tablebody"></slot> </tbody> </table> ` }) new Vue({ el: "#app", data: { // 準備初始化數據 list: [{ id: 1, name: '李四' }, { id: 2, name: '張三' }, { id: 3, name: '張飛' }, ] } }) </script> </body>
<body> <div id="app"> <!-- 一、當咱們但願li 的樣式由外部使用組件的地方定義,由於可能有多種地方要使用該組件, 但樣式但願不同 這個時候咱們須要使用做用域插槽 --> <fruit-list :list='list'> <!-- 二、 父組件中使用了<template>元素,並且包含scope="slotProps", slotProps在這裏只是臨時變量 ---> <template slot-scope='slotProps'> <strong v-if='slotProps.info.id==3' class="current"> {{slotProps.info.name}} </strong> <span v-else>{{slotProps.info.name}}</span> </template> </fruit-list> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> /* 做用域插槽 */ Vue.component('fruit-list', { props: ['list'], /* 三、 在子組件模板中,<slot>元素上有一個相似props傳遞數據給組件的寫法msg="xxx", 插槽能夠提供一個默認內容,若是若是父組件沒有爲這個插槽提供了內容,會顯示默認的內容。 若是父組件爲這個插槽提供了內容,則默認的內容會被替換掉 */ template: ` <div> <li :key='item.id' v-for='item in list'> <slot :info='item'>{{item.name}}</slot> </li> </div> ` }); var vm = new Vue({ el: '#app', data: { list: [{ id: 1, name: 'apple' }, { id: 2, name: 'orange' }, { id: 3, name: 'banana' }] } }); </script> </body>
<html> <head> <meta charset="utf-8"> <title>自定義輪播組件</title> </head> <style type="text/css"> * { padding: 0; margin: 0; } #slideshow { width: 800px; height: 400px; margin: 50px auto; border: 1px solid black; position: relative; } </style> <body> <div id="slideshow"> <slides-show :images="images" :index="index" :img-style="imgStyle" :show="show" :hide="hide" :prepagestye="prepagestye" :nextpagestye="nextpagestye" :slideshowstyle="slideshowstyle" @prepage='prepage' @nextpage='nextpage' > </slides-show> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component("slides-show", { props: ['images', 'index', 'slideshowstyle', 'imgStyle', 'show', 'hide', 'prepagestye', 'nextpagestye' ], template: ` <div :style="[slideshowstyle]"> <ul v-for="imgs in images" class="slideTable"> <li v-if="index === imgs.id" :style="[show]"> <img :src="imgs.path" :style="[imgStyle]"> </li> <li v-else :style="[hide]"> <img :src="imgs.path" > </li> </ul> <span :style="[prepagestye]" @click='$emit("prepage")'> <img src = "img/上一頁.png" width="30px"> </span> <span :style="[nextpagestye]" @click='$emit("nextpage")'> <img src = "img/上一頁.png" width="30px"> </span> </div> ` }) new Vue({ // 綁定父元素 el: "#slideshow", data: { // 定義輪播圖片數據 index: 1, images: [{ id: 1, path: 'img/3Dbg01.jpg' }, { id: 2, path: 'img/3Dbg02.jpg' }, { id: 3, path: 'img/3Dbg03.jpg' }, { id: 4, path: 'img/3Dbg04.jpg' } ], // 隱藏顯現 hide: { display: 'none' }, show: { display: 'inline' }, //定義圖片大小 imgStyle: { width: '100%', height: '400px' }, // 上一頁 prepagestye: { width: '35px', position: 'absolute', top: '190px', display: 'inline-block', left: '8px', cursor: 'pointer', }, // 下一頁 nextpagestye: { width: '35px', position: 'absolute', top: '190px', right: '8px', cursor: 'pointer', display: 'inline-block', transform: ' rotate(180deg)', }, slideshowstyle: { position: 'relative', width: '100%', height: '400px' } }, methods: { prepage: function() { console.log('11') if(this.index <= 1){ this.index = this.images.length; }else{ this.index = this.index-1; } }, nextpage: function() { console.log('2') if (this.index >= this.images.length) { this.index = 1; } else { this.index = this.index + 1; } } } }) </script> <!-- <style type="text/css"> .slideshowStyele { position: relative; text-align: center; background-color: #fff; list-style: none; width: 100%; height: auto; width: 30px; height: 30px; transform: rotate(180deg); cursor: pointer; display: inline-block; } </style> --> </body> </html>
https://gitee.com/li_shang_shan/vue-component-learning-dmeoapp