Vue 基礎
Vue 簡介
- Vue 是一套用於構建使用者介面的漸進式框架。
- 與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。
- Vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,Vue 也完全能夠為複雜的單頁應用提供驅動。
# react 是 facebook開發的
# vue 是我們國人開發
vue起步
- 1. 引包
- 2. 啟動 new Vue(options);
插值表示式 一定要 雙括號 -> {{ msg }}
Vue指令
v-text和v-html
- {{ }} 和 v-text 的作用一樣 都是插入值,直接渲染,innerText
- v-html 既能插入值,又能插入標籤 innerhtml
v-bind繫結
v-bind: 相當於 ' : ' 簡寫
v-on事件處理 監聽dom
v-on 簡寫 ' @ '
v-on
事件修飾符
.once
<!-- 點選事件將只會觸發一次 --> <a v-on:click.once="doThis"></a>
為什麼在 HTML 中監聽事件?
你可能注意到這種事件監聽的方式違背了關注點分離 (separation of concern) 這個長期以來的優良傳統。
但不必擔心,因為所有的 Vue.js 事件處理方法和表示式都嚴格繫結在當前檢視的 ViewModel 上,它不會導致任何維護上的困難。
實際上,使用 v-on 有幾個好處:
- 1. 掃一眼 HTML 模板便能輕鬆定位在 JavaScript 程式碼裡對應的方法。
- 2. 因為你無須在 JavaScript 裡手動繫結事件,你的 ViewModel 程式碼可以是非常純粹的邏輯,和 DOM 完全解耦,更易於測試。
- 3. 當一個 ViewModel 被銷燬時,所有的事件處理器都會自動被刪除。你無須擔心如何清理它們。
v-for列表渲染
當 Vue 正在更新使用 v-for 渲染的元素列表時,它預設使用“就地更新”的策略。
如果資料項的順序被改變,Vue 將不會移動 DOM 元素來匹配資料項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染。
這個類似 Vue 1.x 的 track-by="$index"。
這個預設的模式是高效的,但是隻適用於不依賴子元件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key attribute:
<div v-for="item in items" v-bind:key="item.id">
<!-- 內容 -->
</div>
建議儘可能在使用 v-for 時提供 key attribute,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴預設行為以獲取效能上的提升。
因為它是 Vue 識別節點的一個通用機制,key 並不僅與 v-for 特別關聯。後面我們將在指南中看到,它還具有其它用途。
不要使用物件或陣列之類的非基本型別值作為 v-for 的 key。請用字串或數值型別的值。
v-model雙向資料繫結
<p>{{obj.a}} {{obj.b}}</p> <input type="text" v-model="obj.a" > data: obj:{ num : 0, a:1, b:"nima"
}
Vue中表單輸入繫結應用
修飾符
.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">
偵聽器watch的用法
<div id="app">
<h3>{{abc[0].name}}</h3> <button @click="abc[0].name='addpapa'">changer</button>
</div>
<script src="./vue.js"></script> <script > var v = new Vue({ el : '#app', data:{ abc:[ {id:1, name:"123"}, {id:2, name:"bb"}, {id:3, name:"cc"}, ], } // 基本的資料型別可以使用watch直接監聽,複雜資料型別object array 要深度監視 watch:{ // key是屬於data 物件的屬性名,value:監聽後的行為,n_v:新值,o_v:舊值 'mmm':function (n_v,o_v) { console.log(n_v, o_v) }, // 深度監視 object | array 物件。陣列 'abc':{ deep:'true', //這是字串 handler:function (new_v) { console.log(new_v[0].name); } } }
計算屬性之computed getter
計算屬性之computed的setter方法
<div id="app"> {{content}} </div> <script src="./vue.js"></script> <script> // 全域性的 過濾器 Vue.filter("m_reverse",(val) => { console.log(this) return val.split("").reverse().join("") }) new Vue({ el:'#app', data:{ msg:"", }, methods:{ input_mgs:function (event) { const {value} = event.target; this.content = value; }, click_mgs:function () { console.log(this.content) } }, }) </script>
過濾器 filters
為資料新增新東西
<div id="app"> {{f | my_f("$")}} <br> {{ff | m_reverse}} <br> {{content}} <input type="text" v-model="content" @input="input_mgs"> <button @click="click_mgs" >changer</button> </div> <script src="./vue.js"></script> <script> // 全域性的 過濾器 Vue.filter("m_reverse",(val) => { console.log(this) return val.split("").reverse().join("") }) new Vue({ el:'#app', data:{ msg:"", f:123, ff:"aadddd", }, methods:{ input_mgs:function (event) { const {value} = event.target; this.content = value; }, click_mgs:function () { console.log(this.content) } }, // 區域性的 過濾器 filters:{ my_f:function (f,a) { return a+f } }, computed:{ content:{ set:function (new_v) { this.msg = new_v console.log(new_v) }, get:function () { return this.msg } }, }, }) </script>
音樂播放器
練手專案:音樂播放器
<head> <meta charset="UTF-8"> <title>音樂播放器</title> <style> *{ padding: 0; margin: 0; } ul { list-style: none; } ul li{ margin: 30px 30px; padding: 20px 10px; border-radius: 20px; } ul li.active{ background-color: lavender; } </style> </head> <body> <div id="app"> <audio :src="get_src" controls autoplay @ended="handleend()" ></audio> <ul> <li :class="{active:index === dataindex}" v-for='(item, index) in musicData' :key="item.id" @click="handleClick(index)"> <h3>{{item.id}} 歌名: {{item.name}} </h3> <p>作者: {{item.author}}</p> </li> </ul> <button @click="handlenext()">下一首</button> </div> <script src="./vue.js" ></script> <script > const musicData = [ { id:0, name :'信仰', author:'hc', src:'./static/信仰.mp3' }, { id:1, name :'春嬌與志明', author:'hc', src:'./static/春嬌與志明.m4a' }, { id:2, name :'暗示分離', author:'輝哥', src:'./static/暗示分離.mp3' }, { id:3, name :'突然的自我', author:'hc', src:'./static/突然的自我.mp3' }, { id:4, name :'風吹麥浪', author:'hc', src:'./static/風吹麥浪.m4a' } ] new Vue({ // 繫結 標籤 el: "#app", data:{ musicData, // src:"./static/信仰.mp3", dataindex: 0, }, // vue 的計算屬性 computed:{ get_src(){ return this.musicData[this.dataindex].src }, }, methods:{ handleClick(index){ // this.src = src this.dataindex = index }, handleend(){ this.handlenext(); }, handlenext(){ this.dataindex++ if (this.dataindex ===this.musicData.length){ this.dataindex = 0 } // this.src = this.musicData[this.dataindex].src } } }) </script>
元件
區域性元件的建立和使用
- App 元件 html+css+js
- 1. 建立元件
- 2. 掛載子元件
- 建,掛,用
- 注意: 在元件中這個data 必須是一個函式,返回一個物件
<div id="App"> <!-- // 3. 使用子元件--> <App></App> </div> <script src="../vue.js" ></script> <script> // 以首字母開頭大寫 , 第一個引數是元件名,第二個是 模板 Vue.component("Vheader",{ template: ` <div>我是導航欄 </div> ` }) Vue.component('Vaside',{ template:` <div> 我是側邊欄 </div> ` }) // 需要用到的區域性變數,程式碼需要寫在 建立好的子元件前面 const Vbutton={ template:` <button>區域性按鈕</button> ` } // 區域性組價 const Vcontent={ data(){ return{} }, template:` <div> <div>我是內容欄</div> <Vbutton/> <Vbutton/> </div> `, components:{ Vbutton, }, } // App 元件 html+css+js // 1. 建立元件 // 2. 掛載子元件 // 建,掛,用 // 注意: 在元件中這個data 必須是一個函式,返回一個物件 const App ={ data(){ return { msg: "我是App元件" } }, <!-- 一定要有一個閉合的標籤 --> template:` <div> <div> <Vheader> </Vheader> <div> <Vaside /> <Vcontent/> </div> </div> <h3>{{msg}}</h3> <button @click='handleClick'> 按鈕</button> </div> `, methods:{ handleClick(){ this.msg='學習區域性元件'; } }, components: { Vcontent, } } var a = new Vue({ el:'#App', data:{}, components: { // 掛載子元件 App, }, }) </script>
全域性元件的建立和使用
vue 提供的監聽觸發事件 把輸出的值,通過事件丟擲給父元件
this.$emit('inputHandler',val)
$on 繫結事件
$emit 觸發事件
provide 和 inject
<div id="App"> <!-- // 3. 使用子元件--> <App> </App> </div>
<script src="../vue.js" ></script> <script> // provide // inject // 父元件 provide 來提供變數, 然後再子元件中通過inject 來注入變數,無論元件巢狀多深 // 做了箇中間傳遞者的功能 中央事件匯流排 var c = new Vue // 這裡的this 是這個A子元件本身的this Vue.component('AA',{ template:` <div>AA 使用provide 和 inject -> : {{msg}}</div> `, inject:["msg"] }) Vue.component('A',{ // data(){ // return{ // msg:"provide + inject -> A -> AA -> A " // } // }, template: ` <div> <AA></AA> <button @click="countNumber">購物車+1</button> </div> `, methods:{ countNumber(){ // $emit 觸發事件 c.$emit('add',1) } } }) // 這裡的this 是這個B子元件本身的this Vue.component('B',{ data(){ return { number:0 } }, template:` <div> {{number}} </div> `, // 元件建立 created(){ // $on 繫結事件 // $emit 觸發事件 c.$on('add',(n)=>{ this.number+=n; }) } }) const App ={ data(){ return {} }, // 需要繫結一個屬性 ( : 屬性, @ 事件 ) template:` <div> <A></A> <B></B> </div> `, } new Vue({ el:'#App', data:{ }, provide(){ return { msg:"provide + inject -> App-> A -> AA " } }, components: { // 掛載子元件 App, }, }) </script>
匿名插槽
<slot></slot>
具名插槽
<slot name="aa"></slot>
作用域插槽
有時讓插槽內容能夠訪問子元件中才有的資料是很有用的
生命週期
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- activated 啟用
- deactivated 停用
- 需要配合 keep-alive 儲存在記憶體中
- beforeDestroy
- destroyed
<div id="App"> <!-- // 3. 使用子元件--> <App></App> </div>
<script src="../vue.js" ></script> <script> // beforeCreate // created // beforeMount // mounted // beforeUpdate // updated // activated 啟用 // deactivated 停用 // 需要配合 keep-alive 儲存在記憶體中 // beforeDestroy // destroyed Vue.component('test',{ data() { return { msg:"你輝哥哥哥", isRed:false }; }, methods:{ handleClick(){ this.msg = "Appyourpapa"; this.isRed = !this.isRed ; } }, template: ` <div> <button @click="handleClick">改變</button> <h3 :class='{active:isRed}'>{{msg}}</h3> </div> `, beforeCreate(){ console.log("元件建立之前 -> beforeCreate",this.$data ) }, created(){ // 非常重要的事情,在此時傳送ajxa 請求後端資料 console.log("元件建立完成 -> create", this.$data) }, beforeMount(){ console.log("元件掛載之前 -> beforeMount", document.getElementById("app")) }, mounted(){ console.log("元件掛載完成 -> Mount", document.getElementById("app")) }, beforeUpdate(){ console.log("元件更新之前的DOM -> beforeUpdate", ) }, updated(){ console.log("元件更新完成的DOM -> updated", ) }, beforeDestroy(){ console.log("元件銷燬之前的DOM -> beforeDestroy") }, destroyed(){ console.log("元件銷燬完成的DOM -> destroyed") }, activated(){ console.log("元件被激活了 -> activated") }, deactivated(){ console.log("元件被停用了 -> deactivated") }, }) const App ={ data(){ return { isShow:true } }, methods: { clickHandler(){ this.isShow = !this.isShow; }, }, // 一定要有一個閉合的標籤 // 需要繫結一個屬性 ( : 屬性, @ 事件 ) template:` <div> <keep-alive> <test v-if="isShow"></test> </keep-alive> <button @click="clickHandler">銷燬和建立</button> </div> ` } new Vue({ el:'#App', data:{ }, provide(){ return { msg:"provide + inject " } }, components: { // 掛載子元件 App, }, }) </script>
非同步元件載入
<script src="../vue.js" ></script> <script type='module'> const App ={ data(){ return { isShow:false } }, methods: { clickHandler(){ this.isShow = !this.isShow; }, }, components:{ test:()=>import('./test.js') }, template:` <div> <test v-if="isShow"></test> <button @click="clickHandler">非同步載入</button> </div> `, } new Vue({ el:'#App', data:{ }, provide(){ return { msg:"provide + inject " } }, components: { App, }, }) </script>
refs的使用
訪問子元件例項或子元素
有的時候你仍可能需要在 JavaScript 裡直接訪問一個子元件。為了達到這個目的,你可以通過ref
這個 attribute 為子元件賦予一個 ID 引用。例如:
<base-input ref="usernameInput"></base-input>
現在在你已經定義了這個ref
的元件裡,你可以使用:
this.$refs.usernameInput
來訪問這個`<base-input>
`例項,以便不時之需。比如程式化地從一個父級元件聚焦這個輸入框。在剛才那個例子中,該<base-input>
元件也可以使用一個類似的ref
提供對內部這個指定元素的訪問,例如:
<input ref="input">
甚至可以通過其父級元件定義方法:
methods: {
// 用來從父級元件聚焦輸入框
focus: function () {
this.$refs.input.focus()
}
}
允許父級元件通過下面的程式碼聚焦 `<base-input>
`裡的輸入框:
this.$refs.usernameInput.focus()
當ref
和v-for
一起使用的時候,你得到的 ref 將會是一個包含了對應資料來源的這些子元件的陣列。
nextTick的使用 和應用
<div id="App"> <!-- // 3. 使用子元件--> <App></App> </div>
<script src="../vue.js" ></script> <script >
// 在頁面上拉取一個介面,這個介面返回一些資料,這些資料是這個頁面的一個浮層元件要依賴的, // 然後我在介面一返回資料就展示了這個浮層元件,展示的同時 // 上報一些資料給後臺(這些資料是父元件從介面拿的) // 這個時候,神奇的事情發生了,雖然拿到了資料,但是浮層展現的時候, // 這些資料還未更新到元件去,上報失敗 const Pop = { data(){ return{ isShow:false, } }, props:{ name : { type: String, default:'', }, }, template:` <div v-if="isShow"> {{name}} </div> `, methods:{ show(){ // 彈窗元件展示 this.isShow = true; console.log(this.name); } } } const App=({ data(){ return{ name :"" } }, created(){ // 模擬非同步請求 setTimeout(()=>{ // 更新資料 this.name = "huige" this.$nextTick(()=>{ this.$refs.pop.show(); }) // this.$refs.pop.show(); },1000); }, components:{ Pop }, template: ` <pop ref="pop" :name="name"></pop> ` }) var vm = new Vue({ el:'#App', components: { App } }) </script>
物件變更檢測注意事項
<div id="App"> <h3> {{user.name}}, {{user.age}}, {{user.phone}} <button @click="handlerAdd">新增響應式屬性</button> </h3> </div>
<script src="../vue.js" ></script> <script > // Vue 不能檢測物件屬性的新增和刪除 new Vue({ el:'#App', data:{ user:{} }, methods:{ handlerAdd(){ this.user.age = 20 // 新增響應式屬性, 只有 新增或者刪除 有效 // vue 的方法需要都要加 $ //1. Vue.$set(object, key, value) // this.$set(this.user,"age",20) // 2. Object.assign 方法 this.user = Object.assign({}, this.user,{ age:200, phone:110, }) } }, created(){ setTimeout(()=>{ this.user={name:"我是你爸爸"} },2000) }, }) </script>
mixin混入技術
// 一個公共的元件 const mymixin={ data(){ return{ msg:"asd" } },created(){ this.hello(); }, methods:{ hello(){ console.log("hello mixin") } } } new Vue({ el:'#app', data(){ return { msg1:"huige" } }, created(){ console.log("aaa") }, // mixin 來分發Vue 元件中 的可複用 功能! mixins:[mymixin], })
mixin混入技術應用
<div id="app"> </div>
<script src="../vue.js" ></script> <script>
// 模態框 和 提示框 邏輯程式的複用 // 全域性的mixin 每個建立的元件都會被呼叫。 // 用法 Vue.mixin({}) const allData={ data() { return { isShow:false } }, methods:{ allData(){ this.isShow= !this.isShow } } } const MoDuleData= { template:` <div v-if='isShow'> <h1> 模態框 </h1> </div> `, mixins:[allData] } const ToolData = { template:` <div v-if='isShow'> <h4> 提示框 </h4> </div> `, mixins:[allData] } new Vue({ el:'#app', data:{}, components:{ MoDuleData, ToolData, }, template:` <div> <button @click="handlemoduel">模態框</button> <button @click="handletool">提示框</button> <MoDuleData ref='modulea'></MoDuleData> <ToolData ref='toola'></ToolData> </div> `, methods: { handlemoduel(){ this.$refs.modulea.allData(); }, handletool(){ this.$refs.toola.allData(); }, } }) </script>