是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫或既有項目整合。javascript
框架是庫的升級版css
這裏使用cdn方便測試html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="content">
<!-- moustache 小鬍子語法 表達式 能夠放賦值 取值 三元-->
{{ msg }}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 使用官網的vue地址 -->
<script> // 引用vue後會給一個vue構造函數 var vm = new Vue({ // vm === viewModel el: '#content', // 告訴vue管理哪一部分,querySelector "document.querySelector("#content")" data: { // data中的數據會被vm所代理 msg: 'Hello Vue!' // 能夠經過vm.msg獲取對應的呢日用 } })// Object.defineProperty vm.msg = "wjw" // 修改視圖 </script>
</html>
複製代碼
綜上所屬得出了一套模板語法前端
<span>Message:{{msg}}</span>
複製代碼
{{number + 1}}
{{ok?'YES':'NO'}}
{{message.split('').reverse().join('')}}
複製代碼
可是vue的表單元素 input checkbox textarea radio select 非文本處理vue
vue的指令 directive 只是dom上的行間屬性,vue給這類屬性賦予了一些意義,來實現特殊功能全部指令都以v-開頭value屬性默認狀況下回vue忽略掉 selected checked 都沒有意義java
v-model 會將msg賦予輸入框,輸入框的值改變會影響數據node
<input v-model="msg">
<input type="checkbox" v-model="msg1" value="登山">
複製代碼
<p>Using mustache:<span v-html='rawHtml'></spn></p>
複製代碼
<p v-if='seen'>如今看到我了</p>
複製代碼
<div v-bind:id='dynamicld'></div>
複製代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="content"></div>
<input type="text" id="input">
</body>
<script> let obj = {} let temp = {}; document.getElementById("content").innerHTML = obj.name // 'name' 表明屬性 Object.defineProperty(obj,'name',{ configurable:false, //是否可刪除 // writable:true,// 是否可賦值(若是使用set方法,則不能使用) enumerable:true, // 是否可枚舉,也是就for..in.. // value:1,// 值(若是使用get方法,則不能使用) get(){ // 取obj的name會觸發get方法 return temp['name'] }, set(val){// 給obj賦值會觸發get方法 // console.log(val); temp['name'] = val // 改變temp的結果 input.value = val // 將值賦值給輸入框 } }); input.value = obj.name // 頁面一加載,會將調用get方法 input.addEventListener('input',function(){ // 等待輸入框的變化 obj.name = this.value // 當值變化時會調用set方法 document.getElementById("content").innerHTML = obj.name }) </script>
</html>
複製代碼
最後能夠實現雙向綁定的雛形react
vue會循環data中的數據(數據劫持) 依次的增長getter和settergit
let vm = new Vue({
el:'#content',
data:{
a:{}
}
})
複製代碼
可是這時候我想添加一個school方法,發現沒有產生getter和settergithub
使用變量時 先要初始化,不然新加的屬性不會致使頁面刷新
vm.$set(vm.a,"school",'1')// 此方法能夠給對象添加響應式的變化
複製代碼
vm.a = {"school":"heihei",age:8};
複製代碼
去改變數組中的某一項監控不到的,也不能改變數組的長度方法
let vm = new Vue({
el:'#content',
data:{
a:[1,2,3,4,5,6]
}
})
複製代碼
錯誤方法
vm.a[0] =100
vm.a.length -=2
複製代碼
變異方法:pop push shift unshit sort reserve splice
vm.a = vm.a.map(item=>item*3)
複製代碼
vue 提供了一個v-for 解決循環問題 更高效 會複用原有結構
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="content">
<!--要循環誰就在誰身上增長v-for屬性,相似於for...in..-->
<!--默認是value of 數組/ (value,index) of 數組-->
<li v-for="(todo,index) in todos">
<!-- 會改變原始數組的方法,爲變異方法 例如push(),pop()等; 非變異方法,不會改變原始數組,可是會返回一個新數組 -->
{{ todo.text }} {{index+1}}
</li>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 使用官網的vue地址 -->
<script> let vm = new Vue({ el:'#content', data:{ todos: [ { text: '學習 JavaScript' }, { text: '學習 Vue' }, { text: '整個牛項目' } ] } }) </script>
</html>
複製代碼
v-for循環數組 當用for來更新已被渲染的元素時,vue的「就地複用」機制 是不會改變數據項的順序的。要想從新排序,需爲每項添加key屬性(也就是每項惟一的id)
想要改變
會改變原始數組的方法,爲變異方法 例如push(),pop()等; 非變異方法,不會改變原始數組,可是會返回一個新數組
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<div>
<input type="text" v-model="name">
<button @click="add">添加</button>
</div>
<ul>
<li v-for="(item, i) in list">
<input type="checkbox"> {{item.name}}
</li>
</ul>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 使用官網的vue地址 -->
<script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { name: '', newId: 3, list: [ { id: 1, name: '蔬菜' }, { id: 2, name: '奶酪' }, { id: 3, name: '肉' } ] }, methods: { add() { //注意這裏是unshift this.list.unshift({ id: ++this.newId, name: this.name }) this.name = '' } } }); </script>
</div>
</html>
複製代碼
當你輸入湯時
就會變成這個樣子 =>
可是當你換成了key
能夠簡單的這樣理解:加了key(必定要具備惟一性) id的checkbox跟內容進行了一個關聯。是咱們想達到的效果
vue和react的虛擬DOM的Diff算法大體相同,其核心是基於兩個簡單的假設
首先講一下diff算法的處理方法,對操做先後的dom樹同一層的節點進行對比,一層一層對比,以下圖:
即把C更新成F,D更新成C,E更新成D,最後再插入E,是否是很沒有效率?
因此咱們須要使用key來給每一個節點作一個惟一標識,Diff算法就能夠正確的識別此節點,找到正確的位置區插入新的節點。
vue中列表循環需加:key="惟一標識" 惟一標識能夠是item裏面id index等,由於vue組件高度複用增長Key能夠標識組件的惟一性,爲了更好地區別各個組件 key的做用主要是爲了高效的更新虛擬DOM
事件定義以及縮寫
<div id="app">
<button @click="msg"></button>
<button @mousedown="add"></button>
<!--若是不傳遞參數,則不要寫括號會自動傳入事件源,若是寫括號了,要手動傳入$event屬性-->
</div>
let vm = new Vue({
el:"#app",
methods:{
msg(){
console.log(Math.random());
}
}
})
複製代碼
methods和data中的數據會所有放在vm上,並且名字不能衝突,衝突會報錯,methods中的this指向的都是實例
當鼠標指針移動到元素上方,並按下鼠標按鍵(左、右鍵都可)時,會發生 mousedown 事件。
與 click 事件不一樣,mousedown 事件僅須要按鍵被按下,而不須要鬆開便可發生。
當在元素上鬆開鼠標按鍵(左、右鍵都可)時,會發生 mouseup 事件。
與 click 事件不一樣,mouseup 事件僅須要鬆開按鈕。當鼠標指針位於元素上方時,放鬆鼠標按鈕就會觸發該事件。
當鼠標指針停留在元素上方,而後按下並鬆開鼠標左鍵時,就會發生一次 click 事件。
注意:觸發click事件的條件是按下並鬆開鼠標左鍵!,按下並鬆開鼠標右鍵並不會觸發click事件。
三個事件的觸發順序
若在同一個元素上按下並鬆開鼠標左鍵,會依次觸發mousedown、mouseup、click,前一個事件執行完畢纔會執行下一個事件
若在同一個元素上按下並鬆開鼠標右鍵,會依次觸發mousedown、mouseup,前一個事件執行完畢纔會執行下一個事件,不會觸發click事件
若是須要在內聯語句處理器中訪問原生DOM事件。可使用特殊變量$event
,把它傳入到methods
中的方法中。
在Vue中,事件修飾符處理了許多DOM事件的細節,讓咱們再也不須要花大量的時間去處理這些煩惱的事情,而能有更多的精力專一於程序的邏輯處理。在Vue中事件修飾符主要有:
.stop
:等同於JavaScript中的event.stopPropagation()
,防止事件冒泡.prevent
:等同於JavaScript中的event.preventDefault()
,防止執行預設的行爲(若是事件可取消,則取消該事件,而不中止事件的進一步傳播).capture
:與事件冒泡的方向相反,事件捕獲由外到內.self
:只會觸發本身範圍內的事件,不包含子元素.once
:只會觸發一次冒泡事件:嵌套兩三層父子關係,而後全部都有點擊事件,點擊子節點,就會觸發從內至外 子節點-》父節點的點擊事件
<!-- HTML -->
<div id="app">
 <div class="outeer" @click="outer">
 <div class="middle" @click="middle">
 <button @click="inner">點擊我(^_^)</button>
</div>
</div>
 <p>{{ message }}</p>
</div>
let app = new Vue({
el: '#app',
data () {
 return { message: '測試冒泡事件' }
},
 methods: {
 inner: function () {
this.message = 'inner: 這是最裏面的Button'
 },
 middle: function () {
 this.message = 'middle: 這是中間的Div'
 },
 outer: function () {
 this.message = 'outer: 這是外面的Div'
 }
 }
})
複製代碼
防止冒泡事件的寫法是:在點擊上加上.stop至關於在每一個方法中調用了等同於event.stopPropagation(),點擊子節點不會捕獲到父節點的事件
<!-- HTML -->
<div id="app">
 <div class="outeer" @click.stop="outer">
 <div class="middle" @click.stop="middle">
 <button @click.stop="inner">點擊我(^_^)</button>
</div>
</div>
</div>
複製代碼
.prevent
等同於JavaScript的event.preventDefault()
,用於取消默認事件。好比咱們頁面的<a href="#">
標籤,當用戶點擊時,一般在瀏覽器的網址列出#
:
捕獲事件:嵌套兩三層父子關係,而後全部都有點擊事件,點擊子節點,就會觸發從外至內 父節點-》子節點的點擊事件
<!-- HTML -->
<div id="app">
 <div class="outeer" @click.capture="outer">
 <div class="middle" @click.capture="middle">
 <button @click.capture="inner">點擊我(^_^)</button>
</div>
</div>
</div>
複製代碼
修飾符.self
只會觸發本身範圍內的事件,不會包含子元素。
<!-- HTML -->
<div id="app">
 <div class="outeer" @click.self="outer">
 <div class="middle" @click.self="middle">
 <button @click.stop="inner">點擊我(^_^)</button>
</div>
</div>
</div>
複製代碼
若是咱們在@click
事件上添加.once
修飾符,只要點擊按鈕只會執行一次。
在JavaScript事件中除了前面所說的事件,還有鍵盤事件,也常常須要監測常見的鍵值。在Vue中容許v-on
在監聽鍵盤事件時添加關鍵修飾符。記住全部的keyCode
比較困難,因此Vue爲最經常使用的鍵盤事件提供了別名:
.enter
:回車鍵.tab
:製表鍵.delete
:含delete
和backspace
鍵.esc
:返回鍵.space
: 空格鍵.up
:向上鍵.down
:向下鍵.left
:向左鍵.right
:向右鍵鼠標修飾符用來限制處理程序監聽特定的滑鼠按鍵。常見的有:
能夠用以下修飾符開啓鼠標或鍵盤事件監聽,使在按鍵按下時發生響應:
.ctrl
.alt
.shift
.meta
在Vue中能夠經過config.keyCodes
自定義按鍵修飾符別名。例如,因爲預先定義了keycode 116
(即F5
)的別名爲f5
,所以在文字輸入框中按下F5
,會觸發prompt
方法,出現alert
。
<!-- HTML -->
<div id="app">
<input type="text" v-on:keydown.f5="prompt()">
</div>
Vue.config.keyCodes.f5 = 116;
let app = new Vue({
el: '#app',
methods: {
prompt: function() {
alert('我是 F5!');
}
}
});
複製代碼
在Vue中,使用v-on
來給元素綁定事件,而爲了更好的處理邏輯方面的事物,Vue提供了一個methods
。在methods
中定義一些方法,這些方法能夠幫助咱們處理一些邏輯方面的事情。而在這篇文章中,咱們主要介紹了一些事件的修飾符,好比常見的阻止事件冒泡,鍵盤修飾符等。除此以外,還提供了config.keyCodes
提供自定義按鍵修飾符別名。
<a v-bind:href='url'></a>
<a :href='url'></a>
<a v-on:click='doSomething'></a>
<a @click='doSomething'></a>
複製代碼
縮寫後
咱們能夠很直觀的將一個複雜的頁面分割成若干個獨立組件,每一個組件包含組件的邏輯和樣式,再將這些獨立組件完成一個複雜的頁面。這樣既減小了邏輯複雜度,又實現了代碼的重用。頁面是組件的容器,組件自動組合造成完整的界面,當不須要某個組件時,或者想要替換某個組件時,能夠隨時進行替換和刪除,而不影響整個應用的運行。
在vue中例如div、span均可以看作一個組件
通常寫插件的時候全局組件使用的多一些
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<my-handsom></my-handsom>
<my-handsom></my-handsom>
<my-handsom></my-handsom>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> Vue.component("my-handsom",{ //一個對象能夠當作一個組件 data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' }) var vm = new Vue({ el: '#app' }) </script>
</html>
複製代碼
props
組件的參數傳遞
slot
插槽在組件抽象設計中的應用
自定義事件
父子組件的通訊方式
使用基礎 Vue 構造器,建立一個「子類」。參數是一個包含組件選項的對象。
data
選項是特例,須要注意 - 在 Vue.extend()
中它必須是函數
<div id="mount-point"></div>
複製代碼
// 建立構造器
var demo = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 建立 Profile 實例,並掛載到一個元素上。
new demo().$mount('#mount-point')
複製代碼
參數:
{Function} [callback]
{Object} [context]
用法:
在下次 DOM 更新循環結束以後執行延遲迴調。在修改數據以後當即使用這個方法,獲取更新後的 DOM。
// 修改數據
vm.msg = 'Hello'
// DOM 尚未更新
Vue.nextTick(function () {
// DOM 更新了
})
// 做爲一個 Promise 使用 (2.1.0 起新增,詳見接下來的提示)
Vue.nextTick()
.then(function () {
// DOM 更新了
})
複製代碼
2.1.0 起新增:若是沒有提供回調且在支持 Promise 的環境中,則返回一個 Promise。請注意 Vue 不自帶 Promise 的 polyfill,因此若是你的目標瀏覽器不原生支持 Promise (IE:大家都看我幹嗎),你得本身提供 polyfill。
先來一個示例瞭解下關於Vue中的DOM更新以及nextTick
的做用。
模板
<div class="app">
<div ref="msgDiv">{{msg}}</div>
<div v-if="msg1">Message got outside $nextTick: {{msg1}}</div>
<div v-if="msg2">Message got inside $nextTick: {{msg2}}</div>
<div v-if="msg3">Message got outside $nextTick: {{msg3}}</div>
<button @click="changeMsg">
Change the Message
</button>
</div>
複製代碼
Vue實例
**
new Vue({
el: '.app',
data: {
msg: 'Hello Vue.',
msg1: '',
msg2: '',
msg3: ''
},
methods: {
changeMsg() {
this.msg = "Hello world."
this.msg1 = this.$refs.msgDiv.innerHTML
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML
})
this.msg3 = this.$refs.msgDiv.innerHTML
}
}
})
複製代碼
點擊前
點擊後
從圖中能夠得知:msg1和msg3顯示的內容仍是變換以前的,而msg2顯示的內容是變換以後的。其根本緣由是由於Vue中DOM更新是異步的(詳細解釋在後面)。
下面瞭解下nextTick
的主要應用的場景及緣由。
created()
鉤子函數進行的DOM操做必定要放在Vue.nextTick()
的回調函數中在created()
鉤子函數執行的時候DOM 其實並未進行任何渲染,而此時進行DOM操做無異於徒勞,因此此處必定要將DOM操做的js代碼放進Vue.nextTick()
的回調函數中。與之對應的就是mounted()
鉤子函數,由於該鉤子函數執行時全部的DOM掛載和渲染都已完成,此時在該鉤子函數中進行任何DOM操做都不會有問題 。
Vue.nextTick()
的回調函數中。具體緣由在Vue的官方文檔中詳細解釋:
Vue 異步執行 DOM 更新。只要觀察到數據變化,Vue 將開啓一個隊列,並緩衝在同一事件循環中發生的全部數據改變。若是同一個 watcher 被屢次觸發,只會被推入到隊列中一次。這種在緩衝時去除重複數據對於避免沒必要要的計算和 DOM 操做上很是重要。而後,在下一個的事件循環「tick」中,Vue 刷新隊列並執行實際 (已去重的) 工做。Vue 在內部嘗試對異步隊列使用原生的
Promise.then
和MessageChannel
,若是執行環境不支持,會採用setTimeout(fn, 0)
代替。 例如,當你設置vm.someData = 'new value'
,該組件不會當即從新渲染。當刷新隊列時,組件會在事件循環隊列清空時的下一個「tick」更新。多數狀況咱們不須要關心這個過程,可是若是你想在 DOM 狀態更新後作點什麼,這就可能會有些棘手。雖然 Vue.js 一般鼓勵開發人員沿着「數據驅動」的方式思考,避免直接接觸 DOM,可是有時咱們確實要這麼作。爲了在數據變化以後等待 Vue 完成更新 DOM ,能夠在數據變化以後當即使用Vue.nextTick(callback)
。這樣回調函數在 DOM 更新完成後就會調用。
Vue.set( target, propertyName/index, value )
{Object | Array} target
{string | number} propertyName/index
{any} value
this.myObject.newProperty = 'hi'
)注意對象不能是 Vue 實例,或者 Vue 實例的根數據對象。
<div id="div">
<p >{{items}}</p>
</div>
<script>
var vm = new Vue({
el:"#div",
data: {
items: ['a', 'b', 'c']
}
});
Vue.set(vm.items,2,"ling")
</script>
複製代碼
Vue.set(vm.items,2,"ling") : 表示 把vm.items 這個數組的下標爲2 的元素,改成"ling"
把數組 ["a","b","c"] 修改 後是 ["a","b","ling"]
<div id="div">
<p>{{person}}</p>
</div>
<script>
var vm = new Vue({
el:"#div",
data: {
person:{
name:"ling",
job:"engineer"
}
},
created:function(){
alert(this.person.age)
}
});
Vue.set(vm.person,"age","26")
</script>
複製代碼
注意:person 是data 裏面的子對象,因此可使用 Vue.set( ) 方法。data 這個根對象就不能使用 set 方法
說明:控制檯能夠在person 裏找到age 這個屬性,說明添加成功 (響應式)
vm.food="chocolate"
alert(vm.food)
控制檯和網頁上的 {{person}} 都沒有顯示food 這個屬性,說明food 這個屬性沒有被添加 (非響應式)
Vue.delete( target, propertyName/index )
{Object | Array} target
{string | number} propertyName/index
僅在 2.2.0+ 版本中支持 Array + index 用法。
在 2.2.0+ 中一樣支持在數組上工做。
data:{
namelist : {
id : 1,
name : '葉落森'
}
}
複製代碼
// 刪除name
delete this.namelist.name;//js方法
Vue.delete(this.namelist,'name');//vue方法
複製代碼
容許你自定義過濾器,可被用於一些常見的文本格式化。過濾器能夠用在兩個地方:雙花括號插值和 v-bind
表達式 (後者從 2.1.0+ 開始支持)。過濾器應該被添加在 JavaScript 表達式的尾部,由「管道」符號指示
一、在Vue中使用過濾器(Filters)來渲染數據是一種頗有趣的方式。
二、首先咱們要知道,Vue中的過濾器不能替代Vue中的methods
、computed
或者watch
,
三、過濾器不改變真正的data
,而只是改變渲染的結果,並返回過濾後的版本。
四、在不少不一樣的狀況下,過濾器都是有用的,好比儘量保持API響應的乾淨,並在前端處理數據的格式。
五、在你但願避免重複和鏈接的狀況下,它們也能夠有效地封裝成可重用代碼塊背後的全部邏輯。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<div>{{ message | capitalize }}</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm= new Vue({ el: '#app', data: { message: 'world' }, filters: { // 能夠有好多的自定義過濾器 capitalize(value) { // 這裏的this指向的window if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } }); </script>
</html>
複製代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
{{ message | filterA | filterB }}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm= new Vue({ el: '#app', data: { message: 'world' }, filters: { // 能夠有好多的自定義過濾器 filterA(value){ return value.split('').reverse().join(''); }, filterB(value){ return value.charAt(0).toUpperCase() + value.slice(1) } } }); </script>
</html>
複製代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
{{ message | filterA('hello',hi) }}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm= new Vue({ el: '#app', data: { hi:'!', message: 'world' }, filters: { // 能夠有好多的自定義過濾器 filterA(value1,value2,value3){ return `${value2} ${value1} ${value3}`; } } }); </script>
</html>
複製代碼
這裏,filterA 被定義爲接收三個參數的過濾器函數。其中 message 的值做爲第一個參數,普通字符串 'hello' 做爲第二個參數,表達式 hi 的值做爲第三個參數。
模板中只能有一個根元素
HTML內容模板(template)元素是一種用於保存客戶端內容機制,該內容在加載頁面時不會呈現,但隨後能夠在運行時使用JavaScript實例化。
<div id="app">
<modal></modal>
</div>
<template id="modal">
<div>
<h1>是否刪除</h1>
</div>
</template>
複製代碼
let modal = {
template:"#modal"
}
const app = new Vue({
el:'#app',
components:{
modal
},
data:{
}
})
複製代碼
咱們一般是想把h1的值動態放入,因此就要用到插槽
首先是單個插槽,單個插槽是vue的官方叫法,可是其實也能夠叫它默認插槽,或者與具名插槽相對,咱們能夠叫它匿名插槽。由於它不用設置name屬性。 單個插槽能夠放置在組件的任意位置,可是就像它的名字同樣,一個組件中只能有一個該類插槽。相對應的,具名插槽就能夠有不少個,只要名字(name屬性)不一樣就能夠了。
<div id="app">
<modal>
<h1>插入成功</h1>
</modal>
</div>
<template id="modal">
<div>
<slot></slot>
</div>
</template>
複製代碼
當咱們看到插入成功的時候,匿名插入就實現了
匿名插槽沒有name屬性,因此是匿名插槽,那麼,插槽加了name屬性,就變成了具名插槽。具名插槽能夠在一個組件中出現N次,出如今不一樣的位置。下面的例子,就是一個有兩個具名插槽和單個插槽的組件,這三個插槽被父組件用同一套css樣式顯示了出來,不一樣的是內容上略有區別。
簡單的來講,就是,咱們可能遇到一個問題 咱們想插入不一樣的插槽內的內容不同
在 2.6.0+ 中已棄用
<div id="app">
<modal>
<h1>插入成功</h1>
<h2 slot="title">標題</h2>
<h2 slot="content">內容</h2>
</modal>
</div>
<template id="modal">
<div>
<slot name="default"></slot>
<slot name="title"></slot>
<slot name="content"></slot>
</div>
</template>
複製代碼
咱們能夠發現沒有name的狀況下,默認就是default
最後,就是咱們的做用域插槽。這個稍微難理解一點。官方叫它做用域插槽,實際上,對比前面兩種插槽,咱們能夠叫它帶數據的插槽。什麼意思呢,就是前面兩種,都是在組件的template裏面寫
在 2.6.0+ 中已棄用
這種寫法,習慣了element-ui的朋友必定就很熟悉了。
總結:
1 . 使用slot能夠在自定義組件內插入原生HTML元素,須要搭配使用name和slot屬性,不然多個slot可能會返回重複的HTML元素。
2 . 使用slot-scope能夠將slot內部的做用域指向該子組件,不然默認做用域指向調用slot的父組件。
從 vue@2.6.x 開始,Vue 爲具名和範圍插槽引入了一個全新的語法,即咱們今天要講的主角:
v-slot
指令。目的就是想統一slot
和scope-slot
語法,使代碼更加規範和清晰。既然有新的語法上位,很明顯,slot
和scope-slot
也將會在vue@3.0.x
中完全的跟咱們說拜拜了。而從vue@2.6.0
開始,官方推薦咱們使用v-slot
來替代後二者。
// 組件
Vue.component('lv-hello', {
template: ` <div> <slot name="header"></slot> <h1>個人天呀</h1> </div>`
})
new Vue({
el: '#app1',
data: {
}
});
複製代碼
老版本
<div id="app1">
<!-- 老版本使用具名插槽 -->
<lv-hello>
<p slot="header">我是頭部</p>
</lv-hello>
</div>
複製代碼
新版本的變化
<!-- 新版本使用具名插槽 -->
<lv-hello>
<!-- 注意:這塊的 v-slot 指令只能寫在 template 標籤上面,而不能放置到 p 標籤上 -->
<template v-slot:header>
<p>我是頭部</p>
</template>
</lv-hello>
</div>
複製代碼
將
v-slot:
替換成#
號
<div id="app">
<lv-hello>
<template #header>
<p>我是頭部</p>
</template>
<!-- 注意: #號後面必須有參數,不然會報錯。即使是默認插槽,也須要寫成 #default -->
<template #default>
<p>我是默認插槽</p>
</template>
</lv-hello>
</div>
複製代碼
所謂做用域插槽,就是讓插槽的內容可以訪問子組件中才有的數據。
Vue.component('lv-hello', {
data: function () {
return {
firstName: '張',
lastName: '三'
}
},
template: ` <div> <slot name="header" :firstName="firstName" :lastName="lastName"></slot> <h1>個人天呀</h1> </div> `
})
複製代碼
<div id="app">
<!-- 老版本使用具名插槽 -->
<lv-hello>
<p slot="header" slot-scope="hh">我是頭部 {{ hh.firstName }} {{ hh.lastName }}</p>
</lv-hello>
<!-- 新版本使用具名插槽 -->
<lv-hello>
<!-- 注意:這塊的 v-slot 指令只能寫在 template 標籤上面,而不能放置到 p 標籤上 -->
<template v-slot:header="hh">
<p>我是頭部 {{ hh.firstName }} {{ hh.lastName }}</p>
</template>
</lv-hello>
</div>
複製代碼
:class 綁定的樣式和class綁定的不衝突
<div v-bind:class="{ active: isActive }"></div>
複製代碼
active
這個 class 存在與否將取決於數據屬性isActive
的 布爾值
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
複製代碼
data: {
classObject: {
active: true,
'text-danger': false
}
}
複製代碼
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
複製代碼
<div v-bind:class="[activeClass, errorClass]"></div>
複製代碼
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
複製代碼
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
複製代碼
不過,當有多個條件 class 時這樣寫有些繁瑣。因此在數組語法中也可使用對象語法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
複製代碼
模板內的表達式很是便利,可是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板太重且難以維護。例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el: '#app', data: { message: 'Hello' } }); </script>
</div>
</html>
複製代碼
這裏的表達式包含3個操做,並非很清晰,因此遇到複雜邏輯時應該使用Vue特帶的計算屬性computed來進行處理。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<div id="example">
{{getMessage}}
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el: '#app', data: { message: 'Hello' }, computed: { // 放在computed中最後也會放在vm上,不能和methods與data重名 getMessage() { return this.message.split('').reverse().join('') } } }); </script>
</div>
</html>
複製代碼
計算屬性能夠依賴其餘計算屬性
計算屬性不只能夠依賴當前Vue 實例的數據,還能夠依賴其餘實例的數據
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app1"></div>
<div id="app2">
{{getMessage}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm= new Vue({ el: '#app1', data: { message: 'World' } }); var vm2 = new Vue({ el: '#app2', data: { message: 'Hello' }, computed: { getMessage() { return `${this.message} ${vm.message}` } } }); </script>
</div>
</html>
複製代碼
每個計算屬性都包含一個getter 和一個setter ,咱們上面的兩個示例都是計算屬性的默認用法, 只是利用了getter 來讀取。
在你須要時,也能夠提供一個setter 函數, 當手動修改計算屬性的值就像修改一個普通數據那樣時,就會觸發setter 函數,執行一些自定義的操做
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="getMessage"> <--模擬修改--!>
{{getMessage}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm= new Vue({ el: '#app', data: { hi:'Hello', message: 'World' }, computed:{ getMessage:{ //get,set方法 // getter get(){ return this.hi + ' ' + this.message }, // setter set(newValue){ console.log('===================================='); console.log(newValue); console.log('===================================='); var names = newValue.split(' '); this.hi = names[0]; this.message = names[names.length - 1]; } } } }); </script>
</html>
複製代碼
絕大多數狀況下,咱們只會用默認的getter 方法來讀取一個計算屬性,在業務中不多用到setter,因此在聲明一個計算屬性時,能夠直接使用默認的寫法,沒必要將getter 和setter 都聲明。
咱們能夠將同一函數定義爲一個方法而不是一個計算屬性,兩種方式的最終結果確實是徹底相同的。只是一個使用getMessage()取值,一個使用getMessage取值。
然而,不一樣的是計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時纔會從新求值。
這就意味着只要 hi尚未發生改變,屢次訪問 getMessage計算屬性會當即返回以前的計算結果,而沒必要再次執行函數。
<!DOCTYPE html>
<html> <head> <meta charset="utf-8" /> <title>vue</title> </head> <body> <div id="app"> <div>{{getMessage}}</div> <div> {{getMessage1()}}</div> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var vm= new Vue({ el: '#app', data: { hi:'Hello', message: 'World' }, computed:{ getMessage(){ //get,set方法 return this.hi + ' ' + this.message //而使用計算屬性,只要title沒變,頁面渲染是不會從新進這裏來計算的,而是使用了緩存。 } }, methods:{ getMessage1(){ return this.hi + ' ' + this.message //進這個方法,再次計算。不是刷新,而是隻要頁面渲染,就會進方法裏從新計算。 } } }); </script> </html> 複製代碼
一個對象,鍵是須要觀察的表達式,值是對應回調函數。值也能夠是方法名,或者包含選項的對象。Vue 實例將會在實例化時調用 $watch()
,遍歷 watch 對象的每個屬性。
爲何必定要有watch,不用能夠嗎?咱們已經有了computed,能不能不去使用?
作一個實驗
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="a">
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el:'#app', data:{ a:"1" }, computed: { a(){ setTimeout(() => { this.a=1; }, 500); } } }) </script>
</html>
複製代碼
不難發如今_異步的狀況下就很差使用了_
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="a">
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
a:""
},
watch: { // 只有值變化的時候纔會觸發 支持異步了,其餘狀況咱們更善於使用
a(newVal,oldVal){ // watch的屬性名字要和觀察的人的名字一致
console.log(newVal);
console.log(oldVal);
}
},
})
</script>
</html>
複製代碼
Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變更:偵聽屬性。當你有一些數據須要隨着其它數據變更而變更時,你很容易濫用 watch
<!DOCTYPE html>
<html> <head> <meta charset="utf-8" /> <title>vue</title> </head> <body> <div id="app"> {{ fullName }} </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> </html> 複製代碼
var vm = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
複製代碼
上面代碼是命令式且重複的。將它與計算屬性的版本進行比較:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
複製代碼
是否是感受優雅不少
雖然計算屬性在大多數狀況下更合適,但有時也須要一個自定義的偵聽器。這就是爲何 Vue 經過 watch 選項提供了一個更通用的方法,來響應數據的變化。當須要在數據變化時執行異步或開銷較大的操做時,這個方式是最有用的。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="something">
{{somethingShow}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el: '#app', data: { something: '', somethingShow:'' }, watch: { something(val){ this.somethingShow = "loading" this.getSomething() } }, methods:{ getSomething(){ setTimeout(() => { this.somethingShow = "hello" }, 1000);// 咱們使用延遲模擬一個網絡請求 } } }) </script>
</html>
複製代碼
vm.$watch( expOrFn, callback, [options] )
觀察 Vue 實例變化的一個表達式或計算屬性函數。回調函數獲得的參數爲新值和舊值。表達式只接受監督的鍵路徑。對於更復雜的表達式,用一個函數取代。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="something">
{{somethingShow}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el: '#app', data: { something: '', somethingShow:'' } }) vm.$watch('something',(newVal,oldVal)=>{// watch的屬性名要和觀察的人名字一致 vm.somethingShow = "loading" console.log('===================================='); console.log(newVal); console.log('===================================='); vm.somethingShow = newVal }) </script>
</html>
複製代碼
組件接受的選項之一 props 是 Vue 中很是重要的一個選項。父子組件的關係能夠總結爲: props down, events up 父組件經過 props 向下傳遞數據給子組件;子組件經過 events 給父組件發送消息。
好比咱們須要建立兩個組件 parent 和 child。須要保證每一個組件能夠在相對隔離的環境中書寫,這樣也能提升組件的可維護性。
這裏咱們先定義父子兩個組件和一個 Vue 對象
var childNode = {
template: `
<div>childNode</div>
`
};
var parentNode = {
template: `
<div>
<child></child>
<child></child>
</div>
`,
components: {
child: childNode
}
};
new Vue({
el: "#example",
components: {
parent: parentNode
}
});
複製代碼
<div id="example">
<parent></parent>
</div>
複製代碼
這裏的 childNode 定義的 template 是一個 div,而且內容是"childNode"字符串。 而在 parentNode 的 template 中定義了 div 的 class 名叫 parent 而且包含了兩個 child 組件。
組件實例的做用域是孤立的。這意味着不能(也不該該)在子組件的模板中直接引用父組件的數據。要讓子組件使用父組件的數據,須要經過子組件的 props 選項。 父組件向子組件傳遞數據分爲兩種方式:動態和靜態,這裏先介紹靜態方式。 子組件要顯示的用 props 聲明它指望得到的數據 修改上例中的代碼,給 childNode 添加一個 props 選項和須要的
forChildMsg
數據; 而後在父組件中的佔位符添加特性的方式來傳遞數據。
var childNode = {
template: ` <div> {{forChildMsg}} </div> `,
props: ["for-child-msg"] // 直接把參數做爲數組放進去
};
var parentNode = {
template: ` <div> <p>parentNode</p> <child for-child-msg="aaa"></child> <child for-child-msg="bbb"></child> </div> `,
components: {
child: childNode
}
};
複製代碼
命名規範
**
對於 props 聲明的屬性,在父組件的 template 模板中,屬性名須要使用中劃線寫法; 子組件 props 屬性聲明時,使用小駝峯或者中劃線寫法均可以;而子組件的模板使用從父組件傳來的變量時,須要使用對應的小駝峯寫法。別擔憂,Vue 可以正確識別出小駝峯和下劃線命名法混用的變量,如這裏的
forChildMsg
和for-child-msg
是同一值。
原則上很簡單,for-child-msg做爲一個變量
var parentNode = {
template: ` <div> <p>parentNode</p> <child :for-child-msg="childMsg1"></child> <child :for-child-msg="childMsg2"></child> </div> `,
components: {
child: childNode
},
data: function() {
return {
childMsg1: "child-1",
childMsg2: "child-2"
};
}
};
複製代碼
在父組件的 data 的 return 數據中的 childMsg1 和 childMsg2 會被傳入子組件中
驗證傳入的 props 參數的數據規格,若是不符合數據規格,Vue 會發出警告。
能判斷的全部種類(也就是 type 值)有: String, Number, Boolean, Function, Object, Array, Symbol
Vue.component("example", {
props: {
// 基礎類型檢測, null意味着任何類型都行
propA: Number,
// 多種類型
propB: [String, Number],
// 必傳且是String
propC: {
type: String,
required: true
},
// 數字有默認值
propD: {
type: Number,
default: 101
},
// 數組、默認值是一個工廠函數返回對象
propE: {
type: Object,
default: function() {
console.log("propE default invoked.");
return { message: "I am from propE." };
}
},
// 自定義驗證函數
propF: {
isValid: function(value) {
return value > 100;
}
}
}
});
let childNode = {
template: "<div>{{forChildMsg}}</div>",
props: {
"for-child-msg": Number
}
};
let parentNode = {
template: ` <div class="parent"> <child :for-child-msg="msg"></child> </div>`,
components: {
child: childNode
},
data() {
return {
// 當這裏是字符串 "123456"時會報錯
msg: 123456
};
}
};
複製代碼
還能夠在 props 定義的數據中加入自定義驗證函數,當函數返回 false 時,輸出警告。 好比咱們把上述例子中的 childNode 的
for-child-msg
修改爲一個對象,幷包含一個名叫validator
的函數,該命名是規定叫validator
的,自定義函數名不會生效
let childNode = {
template: "<div>{{forChildMsg}}</div>",
props: {
"for-child-msg": {
validator: function(value) {
return value > 100;
}
}
}
};
複製代碼
在這裏咱們給for-child-msg
變量設置了validator
函數,而且要求傳入的值必須大於 100,不然報出警告。
props 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,可是不會反過來。這是爲了防止子組件五一修改父組件的狀態。
因此不該該在子組件中修改 props 中的值,Vue 會報出警告。
let childNode = {
template: `<div class="child"> <div> <span>子組件數據</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> </div>`,
props: {
"for-child-msg": String
}
};
let parentNode = {
template: ` <div class="parent"> <div> <span>父組件數據</span> <input v-model="msg"/> </div> <p>{{msg}}</p> <child :for-child-msg="msg"></child> </div>`,
components: {
child: childNode
},
data() {
return {
msg: "default string."
};
}
};
複製代碼
傳遞的過程將短橫分割命名,轉成駝峯命名法便可
這裏咱們給父組件和子組件都有一個輸入框,而且顯示出父組件數據和子組件的數據。當咱們在父組件的輸入框輸入新數據時,同步的子組件數據也被修改了;這就是 props 的向子組件傳遞數據。而當咱們修改子組件的輸入框時,瀏覽器的控制檯則報出錯誤警告
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "forChildMsg"
一般有兩種緣由:
prop 做爲初始值傳入後,子組件想把它當作局部數據來用
prop 做爲初始值傳入後,由子組件處理成其餘數據輸出
定義一個局部變量,並用 prop 的值初始化它
可是因爲定義的 ownChildMsg 只能接受 forChildMsg 的初始值,當父組件要傳遞的值變化發生時,ownChildMsg 沒法收到更新。
let childNode = {
template: ` <div class="child"> <div> <span>子組件數據</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`,
props: {
"for-child-msg": String
},
data() {
return { ownChildMsg: this.forChildMsg };
}
};
複製代碼
這裏咱們加了一個
用於查看 ownChildMsg 數據是否變化,結果發現只有默認值傳遞給了 ownChildMsg,父組件改變只會變化到 forChildMsg,不會修改 ownChildMsg。
因爲是計算屬性,因此只能顯示值,不能設置值。咱們這裏設置的是一旦從父組件修改了 forChildMsg 數據,咱們就把 forChildMsg 加上一個字符串"---ownChildMsg",而後顯示在屏幕上。這時是能夠每當父組件修改了新數據,都會更新 ownChildMsg 數據的。
let childNode = {
template: ` <div class="child"> <div> <span>子組件數據</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`,
props: {
"for-child-msg": String
},
computed: {
ownChildMsg() {
return this.forChildMsg + "---ownChildMsg";
}
}
};
複製代碼
let childNode = {
template: ` <div class="child"> <div> <span>子組件數據</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`,
props: {
"for-child-msg": String
},
data() {
return {
ownChildMsg: this.forChildMsg
};
},
watch: {
forChildMsg() {
this.ownChildMsg = this.forChildMsg;
}
}
};
複製代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">{{message}}</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var app = new Vue({ el: '#app', data: { message: "hello is world" }, beforeCreate() { console.group('beforeCreate 建立前狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); //undefined console.log("%c%s", "color:red", "data : " + this.$data); //undefined console.log("%c%s", "color:red", "message: " + this.message) }, created() { console.group('created 建立完畢狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); //undefined console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 }, beforeMount() { console.group('beforeMount 掛載前狀態===============》'); console.log("%c%s", "color:red", "el : " + (this.$el)); //已被初始化 console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 }, mounted() { console.group('mounted 掛載結束狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); //已被初始化 console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 }, beforeUpdate() { console.group('beforeUpdate 更新前狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, updated() { console.group('updated 更新完成狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, beforeDestroy() { console.group('beforeDestroy 銷燬前狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, destroyed() { console.group('destroyed 銷燬完成狀態===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message) } }) </script>
</html>
複製代碼
chrome
瀏覽器裏打開,F12
看console
就能發現
el 和 data 並未初始化
完成了 data 數據的初始化,el沒有
完成了 el 和 data 初始化
完成掛載
在console控制檯中輸入
app.message= 'hello!!';
複製代碼
咱們在console裏執行下命令對 vue實例進行銷燬。銷燬完成後,咱們再從新改變message的值,vue再也不對此動做進行響應了。可是原先生成的dom元素還存在,能夠這麼理解,執行了destroy操做,後續就再也不受vue控制了。
app.$destroy();
複製代碼
能夠在這加個loading事件,加載的動畫
在這結束loading,還作一些初始化,實現函數自執行
在這發起後端請求,拿回數據,配合路由鉤子作一些事情
你確認刪除XX嗎? destroyed :當前組件已被刪除,清空相關內容
v-if
)v-show
)if操做的是dom show 操做的樣式 若是頻繁切換dom使用v-show,當數據一開時就肯定下來使用v-if更好一些,若是if經過內部指令不會執行了 只有dom從顯示到隱藏 或者隱藏到顯示 才能使用vue的動畫
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<body>
<div id="app">
<span v-if="flag">你看的見我</span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el:'#app', data:{ flag:true } }) </script>
</html>
複製代碼
Vue 提供了 transition
的封裝組件,在下列情形中,能夠給任何元素和組件添加進入/離開過渡
在進入/離開的過渡中,會有 6 個 class 切換。
v-enter
:定義進入過渡的開始狀態。在元素被插入以前生效,在元素被插入以後的下一幀移除。v-enter-active
:定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入以前生效,在過渡/動畫完成以後移除。這個類能夠被用來定義進入過渡的過程時間,延遲和曲線函數。v-enter-to
: 2.1.8版及以上 定義進入過渡的結束狀態。在元素被插入以後下一幀生效 (與此同時 v-enter
被移除),在過渡/動畫完成以後移除。v-leave
: 定義離開過渡的開始狀態。在離開過渡被觸發時馬上生效,下一幀被移除。v-leave-active
:定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時馬上生效,在過渡/動畫完成以後移除。這個類能夠被用來定義離開過渡的過程時間,延遲和曲線函數。v-leave-to
: 2.1.8版及以上 定義離開過渡的結束狀態。在離開過渡被觸發以後下一幀生效 (與此同時 v-leave
被刪除),在過渡/動畫完成以後移除。<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<style> div>div{ width:100px;height: 100px;background: red; } .v-enter{ opacity: 1; } /* 激活的時候 */ .v-enter-avtive{ opacity: 0; transition: 1s linear; } /* 離開 */ .v-leave-active{ opacity: 0; background: black; transition: 1s linear; } </style>
<body>
<div id="app">
<button @click="flag=!flag">切換</button>
<!-- vue自定義的組件 -->
<transition>
<div v-show="flag"></div>
</transition>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el:'#app', data:{ flag:true } }) </script>
</html>
複製代碼
趕上了多個transition的時候,同一個class確定是會衝突的,那麼如何處理呢
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<style> div>div{ width:100px;height: 100px;background: red; } .jw-enter-active { transition: all .3s ease; } .jw-leave-active { transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .jw-enter, .jw-leave-to { transform: translateX(10px); opacity: 0; } </style>
<body>
<div id="app">
<button @click="flag=!flag">切換</button>
<!-- vue自定義的組件 -->
<transition name="jw">
<div v-show="flag"></div>
</transition>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ el:'#app', data:{ flag:true } }) </script>
</html>
複製代碼
簡單的理解就是就 transition有一個name屬性
在css中name-狀態便可調用
Vue 也容許註冊自定義指令。注意,在 Vue2.0 中,代碼複用和抽象的主要形式是組件。然而,有的狀況下,你仍然須要對普通 DOM 元素進行底層操做,這時候就會用到自定義指令。
舉一個栗子:
<!DOCTYPE html>
<html> <head> <meta charset="utf-8" /> <title>vue</title> </head> <body> <div id="app"> <div v-color='flag'>123</div> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var vm = new Vue({ directives:{ color(el,bindings){ //el值指代的是button按鈕 console.log(arguments); el.style.background = bindings.value; } }, el: '#app', data: { flag: 'red' }, methods:{ getSomething(){ return "hello" } } }) </script> </html> 複製代碼
出現如圖狀況
再來個栗子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>vue</title>
</head>
<style> .a{ position: absolute;width: 100px;height: 100px;background: red; } </style>
<body>
<div id="app">
<div class="a" v-drag></div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script> var vm = new Vue({ directives:{ drag(el){ el.onmousedown = function (e) { var disx = e.pageX - el.offsetLeft; var disy = e.pageY - el.offsetTop; document.onmousemove = function (e) { el.style.left = e.pageX - disx +'px'; el.style.top = e.pageX - disy + 'px'; } document.onmouseup = function (e) { document.onmousemove = document.onmousemove = null; } e.preventDefault(); } } }, el: '#app', data: { flag: 'red' }, methods:{ getSomething(){ return "hello" } } }) </script>
</html>
複製代碼
能夠拖動
一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):bind
:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。
inserted
:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
update
:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。
el
:指令所綁定的元素,能夠用來直接操做 DOM 。binding
:一個對象,包含如下屬性:
name
:指令名,不包括 v-
前綴。value
:指令的綁定值,例如:v-my-directive="1 + 1"
中,綁定值爲 2
。oldValue
:指令綁定的前一個值,僅在 update
和 componentUpdated
鉤子中可用。不管值是否改變均可用。expression
:字符串形式的指令表達式。例如 v-my-directive="1 + 1"
中,表達式爲 "1 + 1"
。arg
:傳給指令的參數,可選。例如 v-my-directive:foo
中,參數爲 "foo"
。modifiers
:一個包含修飾符的對象。例如:v-my-directive.foo.bar
中,修飾符對象爲 { foo: true, bar: true }
。oldVnode
:上一個虛擬節點,僅在 update
和 componentUpdated
鉤子中可用。string
ref
被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs
對象上。若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子組件上,引用就指向組件實例:<!-- `vm.$refs.p` will be the DOM node -->
<p ref="p">hello</p>
<!-- `vm.$refs.child` will be the child component instance -->
<child-component ref="child"></child-component>
複製代碼
v-for
用於元素或組件的時候,引用信息將是包含 DOM 節點或組件實例的數組。$refs
也不是響應式的,所以你不該該試圖用它在模板中作數據綁定。若是咱們用jQuery的話,通常性均可以操做dom
$("#id").text('xxx') // 使用Jquery
document.getElementById("id") // 使用原生Dom
複製代碼
如今咱們牛逼了,咱們用vue。那vue中,若是我要獲取Dom,該怎麼作?
這就進入本文的主題ref, $refs,官網解釋:
<div id="app">
<div>{{msg}}</div>
</div>
複製代碼
在JavaScript中咱們習慣了使用document.getElementsByTagName
那麼咱們在vue中呢
<div id="app">
<div ref="msg">{{msg}}</div>
</div>
複製代碼
var vm = new Vue({
el: '#app',
data:{
msg:'hello'
},
mounted() {
// console.log(document.getElementsByTagName("div")[0].innerHTML);
console.log('====================================');
console.log(this.$refs.msg);
console.log('====================================');
}
})
複製代碼