Vue-詳細使用方式
更多使用方式請參考 https://cn.vuejs.org/v2/guide/single-file-components.html
1.Vue實例
1.1.創建Vue實例
每個 Vue 應用都是通過用 Vue
函數創建一個新的 Vue 實例開始的:
var abc = new Vue({ //定義的函數變量,隨便寫
// 選項
})
在構造函數中傳入一個對象,並且在對象中聲明各種Vue需要的數據和方法,包括:
- el
- data
- methods
等等
1.2.模板或元素
每個Vue實例都需要關聯一段Html模板,Vue會基於此模板進行視圖渲染。
我們可以通過el屬性來指定。
例如一段html模板:
<div id="abc">
</div>
然后創建Vue實例,關聯這個div
```js
var vue11 = new Vue({
el:"#abc"
})
這樣,Vue就可以基於id為abc
的div元素作為模板進行渲染了。在這個div范圍以外的部分是無法使用vue特性的。
1.3.數據
當Vue實例被創建時,它會嘗試獲取在data中定義的所有屬性,用於視圖的渲染,並且監視data中的屬性變化,當data發生改變,所有相關的視圖都將重新渲染,這就是“響應式“系統。
html:
<div id="abc">
<input type="text" v-model="name"/>
</div>
js:
var vue222 = new Vue({
el:"#abc",
data:{
name:"caicai"
}
})
- name的變化會影響到
input
的值 - input中輸入的值,也會導致vue222 中的name發生改變
1.4.方法
Vue實例中除了可以定義data屬性,也可以定義方法,並且在Vue的作用范圍內使用。
html:
<div id="abc">
{{num}}
<button @click="add">加</button>
</div>
js:
var v11 = new Vue({
el:"#abc",
data:{
num: 0
},
methods:{
add:function(){
// this代表的當前vue實例
this.num++;
},
test(){ //還可以以這樣的方式去定義
// this代表的當前vue實例
this.num++;
}
}
})
1.5.生命周期鈎子
1.5.1.生命周期
每個 Vue 實例在被創建時都要經過一系列的初始化過程 :創建實例,裝載模板,渲染模板等等。Vue為生命周期中的每個狀態都設置了鈎子函數(監聽函數)。每當Vue實例處於不同的生命周期時,對應的函數就會被觸發調用。
生命周期:
1.5.2.鈎子函數
例如:created代表在vue實例創建后;
我們可以在Vue中定義一個created函數,代表這個時期的構造函數:
- created 初始話函數
html:
<div id="abc">
{{hello}}
</div>
js:
var vm = new Vue({
el:"#abc",
data:{
hello: '' // hello初始化為空
},
created(){
this.hello = "hello, world!";
}
})
1.5.3.this
我們可以看下在vue內部的this變量是誰,我們在created的時候,打印this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="vue-test">
<h1>你好,{{name}}</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
//生成一個vue實例
var test_vue = new Vue({
el:"#vue-test", //el 表示element縮寫,就是需要渲染的元素id
data:{ //數據
name:"",
},
created(){
this.name="hello,world"
console.log(this)
}
})
</script>
</body>
</html>
result
2.指令
什么是指令?
指令 (Directives) 是帶有 v-
前綴的特殊特性。指令特性的預期值是:單個 JavaScript 表達式。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。
例如我們在入門案例中的v-on,代表綁定事件。
2.1.插值表達式
2.1.1.花括號
格式:
{{表達式}}
說明:
- 該表達式支持JS語法,可以調用js內置函數(必須有返回值)
- 表達式必須有返回結果。例如 1 + 1,沒有結果的表達式不允許使用,如:var a = 1 + 1;
- 可以直接獲取Vue實例中定義的數據或函數
示例:
HTML:
<div id="abc">{{name}}</div>
JS:
var app = new Vue({
el:"#abc",
data:{
name:"James"
}
})
2.1.2.插值閃爍
使用{{}}方式在網速較慢時會出現問題。在數據未加載完成時,頁面會顯示出原始的{{}}
,加載完畢后才顯示正確數據,我們稱為插值閃爍。
將網速調慢一些,然后試試看剛才的案例:
會有等待vuejs 加載完畢之后,才會去渲染數據。
2.1.3.v-text和v-html
使用v-text和v-html指令來替代{{}}
說明:
- v-text:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會作為普通文本輸出
- v-html:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會被渲染
HTML:
<div id="app">
v-text:<span v-text="hello"></span> <br/>
v-html:<span v-html="hello"></span>
</div>
JS:
var vm = new Vue({
el:"#app",
data:{
hello: "<h1>你好,夏天!</h1>"
}
})
result:
並且不會出現插值閃爍,當沒有數據時,會顯示空白。
2.2.v-model
剛才的v-text和v-html可以看做是單向綁定,數據影響了視圖渲染,但是反過來就不行。接下來學習的v-model是雙向綁定,視圖(View)和模型(Model)之間會互相影響。
既然是雙向綁定,一定是在視圖中可以修改數據,這樣就限定了視圖的元素類型。目前v-model的可使用元素有:
- input
- select
- textarea
- checkbox
- radio
- components(Vue中的自定義組件)
基本上除了最后一項,其它都是表單的輸入項。
舉例:
html:
<div id="app">
<input type="checkbox" v-model="language" value="Java" />Java<br/>
<input type="checkbox" v-model="language" value="PHP" />PHP<br/>
<input type="checkbox" v-model="language" value="Swift" />Swift<br/>
<h1>
你選擇了:{{language.join(',')}} //以“,”進行分割
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
language: []
}
})
</script>
- 多個
CheckBox
對應一個model時,model的類型是一個數組,單個checkbox值是boolean類型 - radio對應的值是input的value值
input
和textarea
默認對應的model是字符串select
單選對應字符串,多選對應也是數組
結果:
2.3.v-on 簡寫 @click
2.3.1.基本用法
v-on指令用於給頁面元素綁定事件。
語法:
v-on:事件名="js片段或函數名" // 簡寫 @click
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="num++">增加</button><br/>
<!--事件指定一個回調函數,必須是Vue實例中定義的函數-->
<button v-on:click="decrement">減少</button><br/>
<h1>num: {{num}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
num:1
},
methods:{
decrement(){
this.num--;
}
}
})
</script>
2.3.2.事件修飾符
在事件處理程序中調用 event.preventDefault()
或 event.stopPropagation()
是非常常見的需求。盡管我們可以在方法中輕松實現這點,但更好的方式是:方法只有純粹的數據邏輯,而不是去處理 DOM 事件細節。
為了解決這個問題,Vue.js 為 v-on
提供了事件修飾符。之前提過,修飾符是由點開頭的指令后綴來表示的。
.stop
:阻止事件冒泡.prevent
:阻止默認事件發生.capture
:使用事件捕獲模式.self
:只有元素自身觸發事件才執行。(冒泡或捕獲的都不執行).once
:只執行一次
2.3.3.按鍵修飾符
在監聽鍵盤事件時,我們經常需要檢查常見的鍵值。Vue 允許為 v-on
在監聽鍵盤事件時添加按鍵修飾符:
<!-- 只有在 `keyCode` 是 13 時調用 `abc.submit()` -->
<input v-on:keyup.13="submit">
記住所有的 keyCode
比較困難,所以 Vue 為最常用的按鍵提供了別名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 縮寫語法 -->
<input @keyup.enter="submit">
全部的按鍵別名:
.enter
.tab
.delete
(捕獲“刪除”和“退格”鍵).esc
.space
.up
.down
.left
.right
2.3.4.組合按鈕
可以用如下修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器。
.ctrl
.alt
.shift
例如:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
2.4.v-for
遍歷數據渲染頁面是非常常用的需求,Vue中通過v-for指令來實現。
2.4.1.遍歷數組
語法:
v-for="item in items"
- items:要遍歷的數組,需要在vue的data中定義好。
- item:迭代得到的數組元素的別名
示例
<div id="app">
<ul>
<li v-for="user in users">
{{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var abc = new Vue({
el:"#app",
data:{
users:[
{name:'小米', gender:'女', age: 21},
{name:'小天', gender:'男', age: 20},
{name:'小冰', gender:'女', age: 24},
{name:'小菲', gender:'男', age: 18},
{name:'小古', gender:'女', age: 25}
]
}
})
</script>
2.4.2.數組角標
在遍歷的過程中,如果我們需要知道數組角標,可以指定第二個參數:
v-for="(item,index) in items"
- items:要迭代的數組
- item:迭代得到的數組元素別名
- index:迭代到的當前元素索引,從0開始。
示例
<div id="app">
<ul>
<li v-for="(user,index) in users">
{{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
2.4.3.遍歷對象
v-for除了可以迭代數組,也可以迭代對象。語法基本類似
語法:
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
- 1個參數時,得到的是對象的值
- 2個參數時,第一個是值,第二個是鍵
- 3個參數時,第三個是索引,從0開始
示例:
<div id="app">
<ul>
<li v-for="(value,key,index) in user">
{{index}} - {{key}} : {{value}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
user:{name:'小兵', gender:'男', age: 21}
}
})
</scr
### 2.4.4.key
當 Vue.js 用 `v-for` 正在更新已渲染過的元素列表時,它默認用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
這個功能可以有效的提高渲染的效率。
但是要實現這個功能,你需要給Vue一些提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 `key` 屬性。理想的 `key` 值是每項都有的且唯一的 id。
示例:
```html
<ul>
<li v-for="(item,index) in items" :key=index></li>
</ul>
- 這里使用了一個特殊語法:
:key=""
我們后面會講到,它可以讓你讀取vue中的屬性,並賦值給key屬性 - 這里我們綁定的key是數組的索引,應該是唯一的
2.5.v-if和v-show
2.5.1.基本使用
v-if,顧名思義,條件判斷。當得到結果為true時,所在的元素才會被渲染。
語法:
v-if="布爾表達式"
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button @click="show = !show">點擊切換</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var abc= new Vue({
el:"#app",
data:{
show:true
}
})
</script>
2.5.2.與v-for結合
當v-if和v-for出現在一起時,v-for優先級更高。也就是說,會先遍歷,再判斷條件。
示例:
<div id="app">
<ul>
<li v-for="(user,index) in users" v-if="user.gender === '女'">
{{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
users:[
{name:'曉曉', gender:'女', age: 21},
{name:'小虎', gender:'男', age: 20},
{name:'小白', gender:'女', age: 24},
{name:'小冰', gender:'女', age: 18},
{name:'肖肖', gender:'女', age: 25}
]
}
})
</script>
結果:
5.5.3.v-else
你可以使用 v-else
指令來表示 v-if
的“else 塊”:
<div v-if="Math.random() > 0.5">
is 哈哈!!!
</div>
<div v-else>
faile!!!
</div>
v-else
元素必須緊跟在帶 v-if
或者 v-else-if
的元素的后面,否則它將不會被識別。
v-else-if
,顧名思義,充當 v-if
的“else-if 塊”,可以連續使用:
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
類似於 v-else
,v-else-if
也必須緊跟在帶 v-if
或者 v-else-if
的元素之后。
2.5.4.v-show
另一個用於根據條件展示元素的選項是 v-show
指令。用法大致一樣:
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show
的元素始終會被渲染並保留在 DOM 中。v-show
只是簡單地切換元素的 CSS 屬性 display
。
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button @click="show = !show">點擊切換</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true
}
})
</script>
2.6.v-bind
2.6.1.綁定class樣式
假如我們想動態的修改頁面元素的屬性,比如class屬性,這樣寫是錯誤的:
<div class="{{isAcctive}}"></div>
因為插值表達式不能用在屬性的值中。
Vue對class屬性進行了特殊處理,可以接收數組或對象格式:
數組語法
我們可以借助於v-bind
指令來實現:
HTML:
<div v-bind:class="isActive"></div> //可以簡寫 <div :class="isActive"></div>
你的data屬性:
data:{
isActive:['active','hasError']
}
渲染后的效果:
<div class="active hasError"></div>
對象語法
我們可以傳給 v-bind:class
一個對象,以動態地切換 class:
<div v-bind:class="{ active: isActive }"></div>
上面的語法表示 active
這個 class 存在與否將取決於數據屬性 isActive
的 truthiness。
你可以在對象中傳入更多屬性來動態切換多個 class。此外,v-bind:class
指令也可以與普通的 class 屬性共存。當有如下模板:
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
和如下 data:
data: {
isActive: true,
hasError: false
}
結果渲染為:
<div class="static active"></div>
當 isActive
或者 hasError
變化時,class 列表將相應地更新。例如,如果 hasError
的值為 true
,class 列表將變為 "static active text-danger"
。
2.6.2.簡寫
v-bind:class
可以簡寫為:class
2.7.計算屬性
在插值表達式中使用js表達式是非常方便的,而且也經常被用到。
但是如果表達式的內容很長,就會顯得不夠優雅,而且后期維護起來也不方便,例如下面的場景,我們有一個日期的數據,但是是毫秒值:
data:{
birthday:1529032123201 // 毫秒值
}
我們在頁面渲染,希望得到yyyy-MM-dd的樣式:
<h1>您的生日是:{{
new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
}}
</h1>
雖然能得到結果,但是非常麻煩。
Vue中提供了計算屬性,來替代復雜的表達式:
var abc= new Vue({
el:"#app",
data:{
birthday:1429032123201 // 毫秒值
},
computed:{ // Vue中的計算屬性
birth(){// 計算屬性本質是一個方法,但是必須返回結果
const d = new Date(this.birthday);
return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
}
}
})
- 計算屬性本質就是方法,但是一定要返回數據。然后頁面渲染時,可以把這個方法當成一個變量來使用。
頁面使用:
<div id="app">
<h1>您的生日是:{{birth}} </h1>
</div>
2.8.watch
watch可以讓我們監控一個值的變化。從而做出相應的反應
示例:
<div id="app">
<input type="text" v-model="message">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:""
},
watch:{
message(newVal, oldVal){//兩個參數,一個是新的值,一個就老的值
console.log(newVal, oldVal);
}
}
})
</script>
3.組件化
在大型應用開發的時候,頁面可以划分成很多部分。往往不同的頁面,也會有相同的部分。例如可能會有相同的頭部導航。
但是如果每個頁面都獨自開發,這無疑增加了我們開發的成本。所以我們會把頁面的不同部分拆分成獨立的組件,然后在不同頁面就可以共享這些組件,避免重復開發。
3.1.定義全局組件
我們通過Vue的component方法來定義一個全局組件。
<div id="app">
<!--使用定義好的全局組件-->
<counter></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
// 定義全局組件,兩個參數:1,組件名稱。2,組件參數
Vue.component("counter",{
template:'<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
data(){
return {
count:0
}
}
})
var app = new Vue({
el:"#app"
})
</script>
- 組件其實也是一個Vue實例,因此它在定義時也會接收:data、methods、生命周期函數等
- 不同的是組件不會與頁面的元素綁定,否則就無法復用了,因此沒有el屬性。
- 但是組件渲染需要html模板,所以增加了template屬性,值就是HTML模板
- 全局組件定義完畢,任何vue實例都可以直接在HTML中通過組件名稱來使用組件了。
- data的定義方式比較特殊,必須是一個函數。
3.2.組件的復用
定義好的組件,可以任意復用多次:
<div id="app">
<!--使用定義好的全局組件-->
<counter></counter>
<counter></counter>
<counter></counter>
</div>
你會發現每個組件互不干擾,都有自己的count值。怎么實現的?
組件的data屬性必須是函數!
當我們定義這個<counter>
組件時,它的data 並不是像這樣直接提供一個對象:
data: {
count: 0
}
取而代之的是,一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝:
data: function () {
return {
count: 0 //在return里面寫相關的值
}
}
如果 Vue 沒有這條規則,點擊一個按鈕就會影響到其它所有實例!
3.3局部注冊
一旦全局注冊,就意味着即便以后你不再使用這個組件,它依然會隨着Vue的加載而加載。
因此,對於一些並不頻繁使用的組件,我們會采用局部注冊。
我們先在外部定義一個對象,結構與創建組件時傳遞的第二個參數一致:
const counter = {
template:'<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
data(){
return {
count:0
}
}
};
然后在Vue中使用它:
var app = new Vue({
el:"#app",
components:{
counter:counter // 將定義的對象注冊為組件
}
})
- components就是當前vue對象子組件集合。
- 其key就是子組件名稱
- 其值就是組件對象的屬性
- 效果與剛才的全局注冊是類似的,不同的是,這個counter組件只能在當前的Vue實例中使用
3.4.組件通信
通常一個單頁應用會以一棵嵌套的組件樹的形式來組織:
- 頁面首先分成了頂部導航、左側內容區、右側邊欄三部分
- 左側內容區又分為上下兩個組件
- 右側邊欄中又包含了3個子組件
各個組件之間以嵌套的關系組合在一起,那么這個時候不可避免的會有組件間通信的需求。
3.4.1.父向子傳遞props
比如我們有一個子組件:
Vue.component("introduce",{
// 直接使用props接收到的屬性來渲染頁面
template:'<h3>{{title}}</h3>',
props:[title] // 通過props來接收一個父組件傳遞的屬性
})
- 這個子組件中要使用title屬性渲染頁面,但是自己並沒有title屬性
- 通過props來接收父組件屬性,名為title
父組件使用子組件,同時傳遞title屬性:
<div id="app">
<h1>打個招呼:</h1>
<!--使用子組件,同時傳遞title屬性-->
<introduce title="大家好,我是caicai"/>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component("introduce",{
// 直接使用props接收到的屬性來渲染頁面
template:'<h1>{{title}}</h1>',
props:['title'] // 通過props來接收一個父組件傳遞的屬性
})
var app = new Vue({
el:"#app"
})
</script>
3.4.2.傳遞復雜數據
我們定義一個子組件:
const myList = {
template:'\
<ul>\
<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
</ul>\
',
props:{ // 通過props來接收父組件傳遞來的屬性
items:{// 這里定義items屬性
type:Array,// 要求必須是Array類型
default:[] // 如果父組件沒有傳,那么給定默認值是[]
}
}
}
- 這個子組件可以對 items 進行迭代,並輸出到頁面。
- 但是組件中並未定義items屬性。
- 通過props來定義需要從父組件中接收的屬性
- items:是要接收的屬性名稱
- type:限定父組件傳遞來的必須是數組,否則報錯
- default:默認值
- items:是要接收的屬性名稱
我們在父組件中使用它:
<div id="app">
<h2>選擇的課程:</h2>
<!-- 使用子組件的同時,傳遞屬性,這里使用了v-bind,指向了父組件自己的屬性lessons -->
<my-list :items="lessons"/>
</div>
var app = new Vue({
el:"#app",
components:{
myList // 當key和value一樣時,可以只寫一個
},
data:{
lessons:[
{id:1, name: 'a'},
{id:2, name: 'b'},
{id:3, name: 'c'},
]
}
})
3.4.3.子向父的通信
來看這樣的一個案例:
<div id="app">
<h2>num: {{num}}</h2>
<!--使用子組件的時候,傳遞num到子組件中-->
<counter :num="num"></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component("counter", {// 子組件,定義了兩個按鈕,點擊數字num會加或減
template:'\
<div>\
<button @click="num++">加</button> \
<button @click="num--">減</button> \
</div>',
props:['num']// count是從父組件獲取的。
})
var app = new Vue({
el:"#app",
data:{
num:0
}
})
</script>
- 子組件接收父組件的num屬性
- 子組件定義點擊按鈕,點擊后對num進行加或減操作
子組件接收到父組件屬性后,默認是不允許修改的。怎么辦?
既然只有父組件能修改,那么加和減的操作一定是放在父組件:
var app = new Vue({
el:"#app",
data:{
num:0
},
methods:{ // 父組件中定義操作num的方法
increment(){
this.num++;
},
decrement(){
this.num--;
}
}
})
但是,點擊按鈕是在子組件中,那就是說需要子組件來調用父組件的函數,怎么做?
我們可以通過v-on指令將父組件的函數綁定到子組件上:
<div id="app">
<h2>num: {{num}}</h2>
<counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>
然后,當子組件中按鈕被點擊時,調用綁定的函數:
Vue.component("counter", {
template:'\
<div>\
<button @click="plus">加</button> \
<button @click="reduce">減</button> \
</div>',
props:['count'],
methods:{
plus(){
this.$emit("inc");
},
reduce(){
this.$emit("dec");
}
}
})
- vue提供了一個內置的this.$emit函數,用來調用父組件綁定的函數