Vue之組件
vue的核心就是組件的使用,玩好了組件才能將前面的基礎更好的運用起來。
組件使我們的項目解耦,更加符合vue的設計思想MVVM。
組件系統是 Vue 的另一個重要概念,因為它是一種抽象,允許我們使用小型、獨立和通常可復用的組件構建大型應用。仔細想想,幾乎任意類型的應用界面都可以抽象為一個組件樹:
例如,你可能會有頁頭,側邊欄,內容區等組件,每個組件又包含了其它的像導航欄鏈接、博文之類的組件
組件的創建
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>組件</title> </head> <body> <div id="app"></div> <script src="vue.js"></script> <script> // Vheader是組件名,最好大寫開頭 Vue.component('Vheader', {
// 和實例對象不一樣,這里data不再返回對象,必須要是個函數,而且必須return data: function () { return { // 必須要return,哪怕是空對象 } }, template: `<div class="header"> <div class="w"> <div class="w1"> <img src="./logo.png"> </div> <div class="w-r"> <button>登陸</button><button>注冊</button> </div> </div> </div>` }); var app = new Vue({ el: '#app', data: {}, computed: {}, methods: {} }) </script> </body> </html>
組件的使用
組件是可服用的Vue實例,並且帶有一個名字,這個例子中是<Vheader> 。
我們可以在一個通過 new Vue 創建的 Vue 根實例中,把這個組件作為自定義元素來使用:
<div id="app"> <Vheader></Vheader> </div>
組件的復用
<div id="app"> <Vheader></Vheader> <Vheader></Vheader> <Vheader></Vheader> </div>
vue-cli腳手架安裝和webpack-simple模板項目生成
vue-cli是一個官方發布vue.js項目腳手架,使用vue-cli可以快速創建vue項目。
安裝nodejs
官網下載安裝
node -v檢查是否安裝成功
npm 是 nodejs package manager ,跟python的pip java mvn一樣
安裝vue-cli
安裝好node之后,我們就可以直接全局安裝vue-cli:
npm install -g vue-cli
安裝慢的話用淘寶鏡像,百度淘寶鏡像
npm install -g cnpm --registry=https://registry.npm.taobao.org
如果安裝失敗使用npm cache clean清理緩存,然后再重新安裝。
安裝完成后vue -V查看vue版本。
vue hlep查看可用命令
vue list查看官方提供的模板
安裝webpack-simple模板
初始化項目,加項目名myProject就創建一個項目名的目錄里生成,不加名字默認再當前目錄生成項目
vue init webpack-simple myProject
最后一步選N,sass是vue的預處理語言還不會。
然后它就告訴你要繼續干什么:
webpack + nodejs 使我們更方便的開發,熱重載。
使用的webpack模板
打開項目myProject,映入眼簾的是一個也看不懂。。。
等等..main.js:
import Vue from 'vue' import App from './App.vue' new Vue({ el: '#app', render: h => h(App) })
可以看出,這個和django的manage.py文件一樣都是一個入口文件。
入口文件引的第一個文件就是App.vue:
看看人家是怎么設計的:
<!--一個組件有三部分組成--> <!-- 一個頁面就把三個部分全部包含了 --> <template> <!--第一部分,頁面的結構--> <!-- 注意template下整個必須是一個閉合標簽,因為他是一個大組件包裹一個個小組件 --> <!-- 比如把下面的注釋去掉就會報錯 --> <!-- <div class="app2"></div> --> <div class="app"> <h3>{{ msg }}</h3> <p>heihei</p> </div> </template> <script> // 第二部分,頁面的業務邏輯 export default { name:'App', // 只是個名字 data(){ // 數據屬性必須是個函數 return { msg:'組件' } }, methods: { }, computed: { } } </script> <style> /*第三部分,css樣式*/ </style>
解耦組件
上面的是一個大組件,要解耦成一個個小組件,所以我們要創建一個存放一個個小組件的文件加。
src下面新建一個folder,就叫components。
並新建三個文件:
每個文件里的結構,跟App.vue里的一樣。
<template> <header class="nav"> <!--footer的class:foot,content:wrap--> 我是header </header> </template> <script> export default { name:'Vheader',// footer:Vfooter,content:content data(){ return { } }, } </script> <style scoped> //scoped:組件里的樣式只在自己的組件里生效 </style>
引入子組件
接下來這些小組件怎么在大組件里用呢:
<template> <div class="app"> <h3>{{ msg }}</h3> <p>heihei</p> <Vcontent></Vcontent> <Vcontent></Vcontent> <Vcontent></Vcontent> </div> </template> <script> // 1. 先引入子組件 import Vcontent from './components/Vcontent.vue' import Vheader from './components/Vheader.vue' import Vfooter from './components/Vfooter.vue' export default { name:'App', data(){ return { msg:'組件' } }, methods: { }, computed: { }, // 2. 掛載組件 components:{ Vheader, // 相當於Vheader:Vheader,key和value相同可以簡寫 Vcontent, Vfooter, } } </script> <style> </style>
組件間傳值
父組件向子組件傳遞數據,通過Prop
1. 父組件向子組件傳值第一步就是, 綁定自定義的屬性,在導入的子組件標簽: <Vheader :title = '父組件中data聲明的數據屬性'/>
2. 父子傳值的第二步就是,要通過props驗證,再子組件里寫這個方法
// 數組類型就必須寫Array,寫Str就會報錯,對應類型可以查官網,然后就可以在子組件里用這個數據量了 props:{ cityArray:Array, }
type
可以是下列原生構造函數中的一個:
-
String
Number
Boolean
Array
Object
Date
Function
Symbol
子組件傳遞數據到父組件,通過自定義事件
1. 子父組件傳值,第一步就是自定義事件
<Vcontent v-on:addCunHandler = 'addHandler'></Vcontent>
2. 給子組件中的某個按鈕綁定原生事件,我們可以調用內建的 this.$emit('自定義的事件名','傳遞的數據'),來向父級組件觸發一個自定義的事件.
methods:{ addCunHandler(){ // 通過$emit觸發自定義事件 // 參數1:自定義事件的名字 // 參數2:數據 this.$emit('addCunHandler','北海北'); } },
MarkDown項目
寫一個markdown項目,練習一下組件傳值
父組件:App.vue
<template> <div class="app"> <Vheader></Vheader> <h2>{{ currentMsg }}</h2> <!-- webpack里的file-loader工具能把圖片看做變量 --> <!-- 所以取圖片用下面這種方式即可 --> <img :src="imgSrc"> <ul> <li v-for = 'item in getArray'> <!-- a標簽里的href="javascript;"表示阻止a標簽的事件,等於a標簽失效了 --> <a href="javascript;">{{item}}</a> </li> </ul> <!-- 來個點擊事件 --> <button @click='clickHandler'>修改</button> <!-- 子父組件傳值,第一步就是自定義事件 --> <Vcontent v-on:addCunHandler = 'addHandler'></Vcontent> <!-- 父子組件傳值,第一步就是綁定自定義屬性 --> <Vfooter :cityArray = 'citys'></Vfooter>
</div> </template> <script> import imgSrc from './assets/logo.png' // 子組件渲染到父組件的第一步就是,導入 import Vheader from './components/Vheader.vue' import Vcontent from './components/Vcontent.vue' import Vfooter from './components/Vfooter.vue' export default { name:'App', data(){ return { msg:'hello world', stars:[ "nsn","alex",'nezha' ], imgSrc:imgSrc, citys:['沙河','通州','西二旗'] } }, methods: { clickHandler(){ this.msg = '哈哈哈', this.stars.push('anglebaby') }, addHandler(str){ this.citys.push(str) } }, // 所有的屬性,都可以被計算屬性綁定起來,多用計算屬性 computed: { currentMsg(){ return this.msg; }, getArray(){ return this.stars } }, // 子組件渲染到父組件的第二步就是,掛載 components:{ Vheader, Vfooter, Vcontent } } </script> <style> *{ padding: 0px; margin: 0px; } </style>
子組件Vfooter
<template> <footer class="foot"> <ul v-for = 'item in cityArray'> <li>{{item}}</li> </ul> </footer> </template> <script> export default { name:'Vfooter', data(){ return { } }, // 父子傳值的第二步就是,一定要通過props驗證 // 數組類型就必須寫Array,寫Str就會報錯,對應類型可以查官網,然后就可以在上面用了 props:{ cityArray:Array, } } </script> <style> </style>
子組件Vcontent
<template> <div class="wrap"> <div class="t"> <button @click='addCunHandler'>添加一個村庄</button> </div> <div class="mark"> <textarea rows="10" cols="100" class="editor" v-model = 'markValue'></textarea> <div class="show" v-html = 'markedValue'></div> </div> </div> </template> <script> // npm install marked --save,別人寫好的markdown工具,直接解析你的markdown語法 import Marked from 'marked' export default { name:'Vcontent', data(){ return { markValue:'' } }, methods:{ // 子組件向父組件傳值,第二步就是觸發自定義事件 addCunHandler(){ // 通過$emit觸發自定義事件 // 參數1:自定義事件的名字 // 參數2:數據 this.$emit('addCunHandler','北海北'); } }, computed:{ markedValue(){ return Marked(this.markValue) } } } </script> <style scoped> .t { width: 300px; height: 100px; } .mark{ width:1210px; height: 600px; margin: 0 auto; } .editor,.show{ float: left; width: 603px; height: 600px; border: 1px solid #666; } </style>
子組件Vheader
<template> <header class="header"> <div class="nav"> <div class="logo"> <img :src="imgSrc" /> </div> <div class="info"> <button>注冊</button> <button>登陸</button> </div> </div> </header> </template> <script> import imgSrc from '../assets/logo.png' export default { name:'Vheader', data(){ return { imgSrc:imgSrc } }, } </script> <style scoped> .header{ width: 100%; height: 40px; background-color: #fff; box-shadow: 0 2px 4px 0 #c9c9c9; /* box-shadow是框邊的陰影,更有立體感*/ } .header .nav{ width: 980px; height: 40px; margin: 0 auto; /*transparent透明*/ background-color: transparent; } .nav .logo{ width: 100px; height: 40px; float: left; } .logo img{ width: 40px; height: 40px; } .nav .info{ float: right; width: 200px; height: 40px; } .info button{ width: 80px; height: 40px; float: left; } </style>