一. Vuecss
一個能夠獨立完成先後端分離式web項的輕量級的JavaScript框架html
三大主流框架之一:Angular React Vue前端
Vue能夠徹底脫離服務器端,之前端代碼複用的方式渲染整個頁面:組件開發vue
二. Vue實例成員web
1. el: 掛載點 data:數據 methods:管理方法 delimiters:分隔符,解決先後臺不分離語言衝突問題 數據庫
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> <style> .box{ background-color: orange; } </style> </head> <body> <div id="app"> <div class="box" v-on:click="pClick">測試</div> <br> <div class="box" v-on:mouseover="pOver">懸浮測試</div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data:{ }, methods:{ pClick (){ alert('box被點擊了') }, pOver (){ alert('鼠標懸浮了?') } } }) </script> </html>
2. computed:計算屬性 一個變量監聽多個變量,而且渲染到頁面中django
1)內部書寫方法, 管理監聽多個變量的方法後端
2)方法名 能夠直接做爲變量被渲染,值爲方法的返回值數組
3)內部只要有一個變量有變化都會被監聽,且方法名對應的值都會被影響【依方法的邏輯】瀏覽器
4)computed用來解決一個變量值依賴多個變量值
兩個案例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <div id="app"> <p>姓<input type="text" v-model="first_name"></p> <p>名<input type="text" v-model="last_name"></p> <p> 全名:{{full_name}}</p> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:'#app', data:{ first_name:'', last_name:'', }, computed:{ full_name (){ return this.first_name + " " + this.last_name; } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <div id="app"> <input type="text" v-model="a_val"> <input type="text" v-model="b_val"> <input type="text" v-model="c_val"> {{c}} </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:'#app', data:{ a_val:'', b_val:'', c_val:'', }, computed:{ c () { //將要監聽的變量放在c方法中 this.a_val; this.b_val; this.c_val; // console.log('該方法被調用了') return this.a_val + this.b_val + this.c_val } } }) </script> </html>
3.watch:監聽屬性
1. watch內部書寫方法,該方法名就是綁定的屬性名,監聽綁定的屬性必需要提早初始化值
2. 方法名錶明的屬性值發生改變,綁定的方法就會被自動觸發/調用,
3. 如full_name屬性值發生變化了,就觸發該方法。如能夠轉跳或向後臺發送數據
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <div id="app"> <p> 姓名<input type="text" v-model="full_name"> </p> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:'#app', data:{ full_name:"", first_name:"", }, watch:{ full_name (){ console.log('我被調用了'); } } }) </script> </html>
4.delimiters:處理差值表達式與後臺模板語言衝突問題,詳見文本指令補充
三. 指令
v-text、v-html、v-html、v-once | v-on | v-bind、v-model | v-if、v-else-if、v-else | v-show
這些指令都是書寫在標籤的頭部,沒有Vue環境都是自定義屬性;有Vue環境就是Vue語法
直接等於一個變量;
v-text
v-html【能夠解析html代碼】
v-html
v-once
v-if
v-else-if
v-else 【前面兩個知足剩下的】
v-model 【綁定value, 單選項框、獨立單選框綁定true與false、多選框綁定數組】
1.簡寫: @ = v-on: | : = v-bind
2. 條件指令,方法methods提供;數據data提供
v-if 頁面消失時不渲染、即不顯示頁面結構; v-if、v-else-if、v-else: 後面跟條件表達式
v-show 頁面消失時以display:none 方式處理
3. 屬性指令:v-bind綁定普通屬性就一個變量,綁定style就是多個變量,key、value形式
v-bind綁定給類屬性
4.循環指令:v-for ="ele in 容器變量" 【案例1=> todolist案例】
數組的循環
<!--傳統點0索引取值-->
<!--for循環,誰要多個,就在哪裏寫for循環-->
<!--能夠取索引,數據在前,索引在後,在Vue中重要的數據在前-->
<!--注:key屬性是vue的屬性,表示該標籤在內存中創建緩存的依據-->
<!--b爲普通屬性,cc就是普通字符串-->
<!--a爲綁定的屬性,msg爲變量,必須在data中定義-->
案列1,
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>循環指令</title> <style> ul{ list-style: none; } /*[v-cloak]{*/ /*display: none;*/ /*}*/ </style> </head> <body> <div id="app" v-cloak> <!--數組的循環--> <div>{{arr}}</div> <hr> <!--傳統點0索引取值--> <ul> <li>{{ arr[0] }}</li> <li>{{ arr[1] }}</li> <li>{{ arr[2] }}</li> </ul> <hr> <!--for循環,誰要多個,就在哪裏寫for循環--> <ul> <li v-for="i in arr">{{i}} </li> </ul> <hr> <!--能夠取索引,數據在前,索引在後,在Vue中重要的數據在前--> <ul> <li v-for="(s, i) in arr">第{{i+1}}個:{{s}}</li> </ul> <hr> <!--注:key屬性是vue的屬性,表示該標籤在內存中創建緩存的依據--> <!--b爲普通屬性,cc就是普通字符串--> <!--a爲綁定的屬性,msg爲變量,必須在data中定義--> <ul> <li v-for="(s, i) in arr" :key="s+i" b="cc" :a="msg">第{{i+1}}個:{{s}}</li> </ul> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:'#app', data:{ arr:['aaa', 'bbb', 'ccc'] }, }) </script> </html>
對象的循環
<!--對象循環只拿val-->
<!--key、value都取,value在前,key在後-->
<!--對象也能夠取索引,默認從0開始-->
<!--列表裏套字典,不能夠放變量,直接放[{}, {}, {}]-->
對象循環案例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>對象循環指令</title> </head> <body> <div id="app"> <ul> <!--對象循環只拿val--> <li v-for="(v) in dict">{{ v}}</li> </ul> <hr> <ul> <!--value在前,key在後--> <li v-for="(v, k) in dict">key:{{k}},值:{{v}}</li> </ul> <hr> <ul> <!--對象也能夠取索引,默認從0開始--> <li v-for="(v, k, index) in dict">key:{{k}},值:{{v}},第{{ index }}</li> </ul> <hr> <!--列表裏套字典--> <p v-for="stu in students"> <span v-for="(val, ke, i) in stu"> <b v-if="i != 0">|</b> <b>{{ ke }}:{{ val }}</b> </span> </p> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el: '#app', data: { dict: { 'name': 'jason', 'gender': 'male', 'age': 17 }, students: [ { 'name': 'owen', 'gender': '哇奧', 'age': 27 }, { 'name': 'jason', 'gender': '哇塞', 'age': 21 }, { 'name': 'egon', 'gender': '我去', 'age': 30 },] } }) </script> </html>
todolist案例
1) 數據爲空直接結束
2)數據添加到留言數組中
this.msg.push(this.msg_val); // 尾增
this.msg.unshift(this.msg_val); //首增
3)清空輸入框
4)操做數組
// this.msg.splice(index, count,arg); // 從第幾位開始,操做多少位,可變長的新數據
// count:0 新增 arg
// count:1,2 修改 成arg
// arg:0 刪除
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>todolist</title> <style> li:hover{ cursor:pointer; color: red; } </style> </head> <body> <div id="app"> <input type="text" v-model="msg_val" > <button @click="send_msg">留言</button> <ul> <li v-for="(v, i) in msg" @click="del_msg">{{v}}</li> </ul> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:"#app", data:{ msg:['第一條', '第二條'], msg_val:"" }, methods:{ send_msg (){ // 1) 數據爲空直接結束 if (!this.msg_val) return; // 2)數據添加到留言數組中 // this.msg.push(this.msg_val); // 尾增 this.msg.unshift(this.msg_val); //首增 // 3)清空輸入框 this.msg_val='' }, del_msg (index){ // this.msg.splice(index, count,arg); // 從第幾位開始,操做多少位,可變長的新數據 // count:0 新增 arg // count:1,2 修改 成arg // arg:0 刪除 this.msg.splice(index, 1) } } }) </script> </html>
5. 文本相關指令:v-text v-html v-once ==>三者後面綁定的都是變量名,【加引號就是普通字符串】 變量名必須在data中定義
{{ msg }} 插值表達式 至關因而標籤的text, 必須由Vue實例的data提供, 不然報not defined
補充:差值表達式與後臺模板語言衝突問題?【先後臺不分離時,如由django的試圖函數加載,致使先後臺數據加載衝突】
解決方式:符號格式化, 非delimiters中的符號不會識別,會以普通字符串處理
delimiters:['[{', '}]'] | delimiters:[ '${', '}$' ]
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <div id="app"> <!--不是delimiters定義的符號,不會被識別--> {{msg}} <!--會被vue識別--> <p>[{ msg }]</p> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:'#app', data:{ msg:"信息" }, delimiters:['[{', '}]'] }) </script> </html>
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
v-text:
<p v-text='msg'>原文本</p> 原文本會被msg替換 ,就是文本
<p v-text='"msg"'>123</p> 加引號就是普通字符串
v- html :
能夠解析標籤,非標籤就解析爲字符串,原文本會被變量替換
<p v-html="htmlMsg" @click="changeMsg">1230000</p>
methods:{
changeMsg:function () {
this.htmlMsg = "<i>htmlMsg被點擊後的</i>"
}
}
v-once:
默認爲初始值,不會被改變
<p v-once="htmlMsg">{{htmlMsg}}</p>
4、前臺數據庫 存取支持點或[ ] 語法
window.localStorage; //永久存儲倉庫【基於服務器的】
window.sessionStorage //臨時存儲倉庫 【瀏覽器關閉,數據就消失】
Cookies 有過時時間的存儲倉庫
localStorage
存: localStorage['name'] = 'owen'
localStorage.name = 'owen'
取 localStorage.name
清空 localStorage.clear()
sessionStorage
存 window.sessionStorage.name ='egon'
取 console.log(window.sessionStorage['name'])
清空 sessionStorage.clear()
優化todolist:
1. 數據庫中有值就存入,沒有值就建立一個空數組, 數據庫中數據存入默認是以字符串形式存入,因此要將字符串split爲數組
msg: localStorage.msg ? localStorage.msg.split(',') :[],
2. 數據刪除後,需同步到數據庫
localStorage.msg = this.msg;
更新後代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>todolist</title> <style> li:hover{ cursor:pointer; color: red; } </style> </head> <body> <div id="app"> <input type="text" v-model="msg_val" > <button @click="send_msg">留言</button> <ul> <li v-for="(v, i) in msg" @click="del_msg">{{v}}</li> </ul> </div> </body> <script src="js/vue.min.js"></script> <script> new Vue({ el:"#app", data:{ // msg:['第一條', '第二條'], msg: localStorage.msg ? localStorage.msg.split(',') :[], msg_val:"" }, methods:{ send_msg (){ // 1) 數據爲空直接結束 if (!this.msg_val) return; // 2)數據添加到留言數組中 // this.msg.push(this.msg_val); // 尾增 this.msg.unshift(this.msg_val); //首增 //同步到數據庫 localStorage.msg = this.msg; // 3)清空輸入框 this.msg_val='' }, del_msg (index){ // this.msg.splice(index, count,arg); // 從第幾位開始,操做多少位,可變長的新數據 // count:0 新增 arg // count:1,2 修改 成arg // arg:0 刪除 this.msg.splice(index, 1); // 刪除後同步到數據庫 localStorage.msg = this.msg; } } }) </script> </html>
5、組件 【每一個組件均由 html模板、css樣式、js邏輯組成】、根組件 | 局部組件 | 全局組件
根組件:new Vue({}) | el做爲template | data 直接綁定{}
局部組件與全局組件:只有一個根標籤 | 必須明確本身的 html(template)、css、js | data是一個函數,函數的返回值是{}
局部組件:let localTag = {template:``, data (){ return {}}, methods:{ func(){}}, } | 必須在父組件註冊才能使用 | js駝峯對應的-連接語法
全局組件:Vue.component(' ', {至關因而一個局部組件}) | 無需註冊 | js駝峯對應的-連接語法
1.一個new Vue建立的是vue實例,一個實例就是一個vue組件
2. new 定義的對象實例稱之爲根組件【實際開發中一個頁面只有一個根組件】
3. 兩個根組件之間數據的是相互隔離的,能夠將new出來的實力賦值給變量,而後利用原生的js來處理,
template:·· 抄寫真實DOM: 用引號包裹,【樣式、事件邏輯都同樣能夠包含】
注:掛載點是必須的(做爲虛擬DOM渲染替換的依據),掛載點能夠讀取掛載點的內容及全部結構,做爲根組件本身的template,因此根組件無需書寫template。
掛載點爲何是必須的? 即便有了本身的template,仍是須要指定替換頁面中的哪一個部分。
至關於:Vue組件將掛載點的內容讀到內存中,而後加載本身的數據,加載完後再用組件的虛擬DOM替換掛載點對應的真實DOM
結論:1.掛載點是必須的,做爲虛擬DOM渲染替換的依據。
2.掛載點讀取掛載點中的內容及結構能夠做爲組件本身的template, 因此template不是必須的。
案例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <div id="app01"> {{msg}} </div> <div id="app02"> {{msg}} </div> </body> <script src="js/vue.min.js"></script> <script> let app01 = new Vue({ el:'#app01', data:{ msg:"我是app01msg", c:'red', // template中的C }, // template:'<ul>{{msg}}</ul>' //替換掛載點對應的真實DOM template:` <div id="app01" :style="{color: c}" @click="action"> {{msg}} </div> ` , //抄寫真實DOM:用引號包裹, methods:{ action (){ alert(this.msg) } } }); let app02 = new Vue({ el:'#app02', data:{ msg:"我是app02msg" } }); // console.log(app01.msg) // app01.msg = app02.msg //根組件間經過原生js在外組件外界進行通訊 </script> </html>
4. 根組件內部能夠註冊使用n個子組件, 子組件必須擁有本身的 html模板、css樣式、js邏輯。
5. 建立局部組件 => 在根組件中註冊 => 解析{} 中的vue語法 => 組件造成
注:new出來的就是根組件, 定義一個對象【 let box= {...}】 局部組件
Vue中取名建議小駝峯,html標籤中標籤名忽略大小寫,都會默認成小寫,這樣Vue中的名字與HTML就對不上了【例】:
錯誤的: Vue中的 html
components:{ <boxTag></boxTag>
boxTag: boxTag
}
建議:1. 都用小寫加下劃線
2. 或者js引號包裹:‘box-tag’ html: box-tag
3. Vue中建議用小駝峯,Html中支技用中線隔開語法,對應着就是JS中的駝峯語法
components中: boxTag html中:box-Tag
6.局部組件data必需要是一個函數,return一個字典,由於每一個組件必需要有一套本身的數據,【data的數據還必須是字典】
相似閉包函數,每執行一次外部函數,內部函數就會產生一個局部名稱空間
閉包案例
# 閉包案例 def outer(): def inner(): num=1 return inner print(inner.__dict__, id(inner)) obj1 = outer() obj2 = outer() {} 2137236028272 {} 2137236028408
Veu局部組件案例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>局部組件</title> <style> .box { width: 200px; text-align: center; border: 1px solid black; border-radius: 10px; overflow: hidden; float: left; } .box img { width: 100%; } .box:hover span { cursor: pointer; color: red; } </style> </head> <body> <div id="app"> <box-tag></box-tag> <box-tag></box-tag> </div> </body> <script src="js/vue.js"></script> <script> let boxTag = { //局部組件 //html模板 template: ` <div class="box"> <img src="img/333.jpg" alt=""> <p> <span @click="btnClick">點擊了下{{ num }}</span> </p> <p>美人</p> </div> `, data() { // 組件執行一次就會產生一個局部名稱空間,來存放本身的一套數據 return { num:0 } }, methods: { btnClick() { this.num++ } } }; new Vue({ el: '#app', components: { // 'box-tag': boxTag boxTag, } }) </script> </html>
6、組件通訊
1. 父傳子,數據在父組件 => 父組件模板寫子組件標籤 =>子組件標籤自定義屬性綁定數據變量
父組件提供數據 | 子組件通props綁定屬性 | 子組件拿到屬性就拿到父組件的變量值, props中能夠當作是一個反射,能夠直接拿到對應的變量值
父傳子案例一:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>父傳子</title> </head> <body> <div id="app"> <sub-tag :a="msg" ></sub-tag> <!--<sub-tag></sub-tag>--> </div> </body> <script src="js/vue.js"></script> <script> let subTag ={ //子組件經過實例成員props獲取自身自定義屬性,經過插值表達式反射拿到對應的變量的值 props:['a'], template:` <div> <h1>{{ a }}</h1> </div> `, // data (){ // return { // msg:'123' //該數據必須由父組傳進來,不能夠寫死 // } // }, }; new Vue({ el:'#app', components:{ subTag, }, data:{ msg:"父級數據" }, }) </script> </html>
父傳子案例二:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> <style> .box{ width: 200px; border-radius: 10px; border: 2px solid black; text-align: center; float: left; overflow: hidden; } .box img{ width: 100%; } .box:hover { cursor: pointer; color: red; } </style> </head> <body> <div id="app"> <sub-tag v-for="box_obj in boxTag" :box-tag="box_obj"></sub-tag> </div> </body> <script src="js/vue.js"></script> <script> let subTag = { props:['boxTag'], template:` <div class="box"> <img :src="boxTag.img_url" alt=""> <span @click="action">點了{{num}}下</span> <p> <span>{{ boxTag.img_title}}</span> </p> </div>> `, data (){ return { num:0 } }, methods:{ action (){ this.num ++ }, }, }; let back_data = [ { img_url:'img/222.jpg', img_title:'美1'}, {img_url:'img/333.jpg', img_title:'美2'}, {img_url:'img/444.jpg', img_title:'美3'}, ]; new Vue({ el:'#app', components:{ subTag, }, data:{ boxTag:back_data, }, }) </script> </html>
2. 子傳父, 數據在子組件 => 父組件模板寫子組件標籤 => 子組件內部經過事件發送數據給外部,子組件與父組件連接的橋樑子組件標籤
子組件提供數據 | 子組件 $emit('自定義事件', 數據們) | 父組件模板中的子組件標籤綁定自定義事件 | 自定義事件的方法由父組件實現 | 實現的方法的參數就是子組件的數據
@send_pag2 子組件的自定義事件、 recv_page2 父組件的變量事件
<view-tag v-if="page == 'tag1'" @send_pag2="recv_page2"></view-tag>
子傳父案例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>父子組件</title> <style> body, h1{ margin: 0; } </style> <style> .header_tag{ height: 120px; background-color: orange; } .body{ height: 800px; background-color: papayawhip; } .footer{ height: 120px; background-color: cyan; } span:hover{ cursor: pointer; color: red; } </style> </head> <body> <div id="app"> <view-tag v-if="page == 'tag1'" @send_pag2="recv_page2"></view-tag> <view-tag2 v-else-if="page == 'tag2'" @send_pag2="recv_page2"></view-tag2> </div> </body> <script src="js/vue.js"></script> <script> let headerTag ={ template:` <div class="header_tag"> <h1 style="text-align: center; line-height: 80px">頭</h1> <span @click="changPage('tag1')" >免費</span> <span @click="changPage('tag2')" >輕課</span> </div> `, methods:{ changPage (page) { this.$emit('send_data', page) }, }, }; let footerTag ={ template:` <div class="footer"> <h1 style="text-align: center; line-height: 120px">尾</h1> </div> `, }; let viewTag = { template:` <div> <header-tag @send_data="rev_sub"></header-tag> <div class="body" style="background-color: green"></div> <footer-tag></footer-tag> </div> `, components:{ headerTag, footerTag, }, methods:{ rev_sub (val){ this.$emit('send_pag2', val) }, }, }; let viewTag2 = { template:` <div> <header-tag @send_data="rev_sub"></header-tag> <div class="body" style="background-color: blue"></div> <footer-tag></footer-tag> </div> `, components:{ headerTag, footerTag, }, methods:{ rev_sub (val){ this.$emit('send_pag2', val) }, }, }; new Vue({ el:'#app', components:{ viewTag, viewTag2, }, data:{ page:'tag1' }, methods:{ recv_page2 (val){ console.log(val); this.page = val; } } }) </script>