Vue專欄 - Vue中的指令
目錄:
筆者挑了一些常用指令來寫寫,比如像v-cloak這類指令, 就被自動忽略啦
-
v-bind
-
v-html
-
v-text
-
v-for
-
v-if, v-else if, v-else
-
v-once
-
v-model
-
v-on
-
自定義指令
指令
我們之前一直有提到Vue框架的侵入性, 那麼他到底侵入在哪裏, 這裏筆者就來寫寫他侵入性的第一種凸顯, 就是你想用Vue框架開發代碼, 想用它來進行點擊事件, 鼠標事件等操作, 你就要按照他的規則來
在以前的原生js開發中, 我們給dom綁定事件的操作如下
const dom = document.querySelector('.wrapper');
dom.onclick = function() {
console.log('我被點擊了');
}
而Vue中, 我們大可不比如此
...
<body>
<div class='wrapper' @click = "handleClick"></div>
<script>
const vm = new Vue({
el: '.wrapper',
methods: {
handleClick() {
console.log('我被點擊了');
}
}
})
</script>
</body>
...
你不必馬上搞懂上面的例子, 咱先混個臉熟
指令是Vue提供給我們的一項比較常用的功能, 他帶有前綴v-
, 指令的職責也就是幫助我們更好的控制一個dom元素,他書寫在我們想要控制的dom元素中, 因爲Vue的虛擬dom緣故, 所以我們也必須儘量少操作原生dom, 這些指令讓我們的開發更加的高效和便捷
那咱們一個一個的來看看吧
v-bind
我們在以前做開發的時候, 肯定會遇到一些業務邏輯, 比如class類名要動態綁定, 或者要給某個dom元素上綁定一定的屬性, 又或者直接跟表單控件的value值進行綁定使其變爲受控組件, 這些業務通常都讓我們大傷腦筋, 倒不是因爲他多難, 只是他寫的代碼着實有點多
比如我現在有個業務, 後臺傳遞過來一個對象, 這個對象是經常會變化的, 該對象有一個name屬性, 我們必須將這個name屬性綁定在類名爲box的dom元素上, 保證每次都穩穩的拿到正確的對象
我們使用原生js的話大致操作如下
...
<body>
<div class='box'></div>
<script>
(function() {
const box = document.querySelector('.box'); // 拿到dom元素
getData() {
ajax('api/getObj', 'GET', resp => {
box.setAttribute('name', resp.name);
})
}
getData();
})()
</script>
</body>
...
在Vue中, v-bind幫我們優雅的處理了這個問題
...
<body>
<!-- !!!v-bind出現在下方的dom元素中 -->
<div class='wrapper' v-bind:name='name'></div>
<script>
const vm = new Vue({
el: '.wrapper',
data: {
name: 'loki'
},
// 這個mounted你現在不必明白他是啥, 同樣, 臉熟就好, 他其實就是會在頁面加載完畢的時候執行, 然後
// 他一執行 getData也執行了
mounted() {
this.getData();
},
methods: {
getData() {
ajax('api/getObj', 'GET', resp => {
this.name = resp.name; // 看起來更加的優雅, 而且也方便維護
})
}
}
})
</script>
</body>
...
v-bind有一個語法糖, 用:
代替v-bind:
v-bind:name='name'
我們可以直接寫成:name='name'
同樣, 我們可以用它來綁定動態class
<div id='app'>
<!-- 介紹兩種常用的綁定類名的方式, 其他的可以自己查看api -->
<!-- box一定會出現在類名中, 而active是否展示取決於isActive是否爲true -->
<div :class="{ 'box': true, 'active': isActive }">
<div :class="[isActive ? 'active': '']">
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
isActive: true
}
})
</script>
對錶單進行控制
// 由此表單成爲了受控組件
<input :value='inputValue' />
上面的綁定的值, 都建立在被Vue實例接管的情況下, 綁定的變量會去Vue實例中尋找, 我就省略沒書寫了
這個v-bind暫時你可能覺得沒大用處, 但是請記住他, 隨着你對vue理解越來越深刻, 它一定是你的座上賓
v-html
v-html 作用其實跟js中的innerHTML完全一致, 就是將v-html所攜帶的值通過html的形式插入到某個dom中
在原生js中, 我們需要改變一個dom元素中的html模板, 一般是如下操作
(function(){
const div = document.querySelector('.wrapper');
div.innerHTML = '<span>helloWorld</span>';
}())
在Vue中, 我們的操作變得很清新脫俗
...
<body>
<!-- !!!v-html出現在下方的dom元素中 -->
<div class='wrapper' v-html = 'htmlStr'></div>
<script>
const vm = new Vue({
el: '.wrapper',
data: {
htmlStr: '<span>helloWorld</span>'
}
})
</script>
</body>
...
這樣我們就實現了同樣功能
v-text
這哥們相信筆者不用過多介紹大家也能夠猜得出他的作用的,沒錯這哥們和innerText如出一轍, 功能也完全一樣
原生js控制innerText操作如下
(function() {
const div = document.querySelector('.wrapper');
div.innerHTML = 'helloWorld';
}())
Vue接管了以後如下
...
<body>
<!-- !!!v-text出現下方的dom元素中 -->
<div class='wrapper' v-text = 'textStr'></div>
<script>
const vm = new Vue({
el: '.wrapper',
data: {
textStr: 'helloWorld'
}
})
</script>
</body>
...
v-for
兩個字, 循環, Vue中的循環很秀, 當我們要將一個數組或者對象循環並且讓他們的值放進dom元素中顯示的時候, 就會要用到他, 同樣來看實例
原生js
(function() {
const arr = ['loki', 'thor'];
const domArr = arr.map(ele => {
var li = document.createElement('li');
li.innerText = ele;
return li;
});
const ul = document.querySelector('ul');
domArr.forEach(ele => ul.appendChild(ele));
}())
Vue v-for
...
<body>
<!-- !!!v-for出現下方的dom元素中 -->
<ul>
<li v-for='name in arr' :key='name'>{{ name }}</li>
</ul>
<script>
const vm = new Vue({
el: 'ul',
data: {
arr: ['loki', 'thor']
}
})
</script>
</body>
...
v-for的語法 就是
v-for="(ele, index) in data" :key="unique value"
v-for
中的in也可以用of代替
-
ele: 遍歷出來的每一項
-
index: 如果是數組, 索引爲數組的index項, 如果是對象, index爲對象的key值非必填
-
data: 被遍歷的數據
-
key: 一個唯一值, 這個key值很重要, 在Vue的底層diff算法中, 他通過key值來更快的尋找到某個虛擬dom並且跟真實dom進行比對, 如果無key值的話, 可能會感知不到變化, 這是diff算法底層的知識, 我可以做個例子演示一波
如果你用數組的index作爲key值, 那麼在某些情況下跟沒有給定key值沒有區別, 還多寫了一些代碼, 如果你不給key值, 那看了代碼讓人覺得頭皮發麻
這裏我給你寫明白了, 讓你看看爲什麼key值不能亂給
...
<body>
<div id="app">
<ul>
<li v-for="(ele, index) in arr" :key="ele">{{ ele }}</li>
</ul>
<!-- 下面的@click馬上就會講到, 這裏混個臉熟, 就是綁定點擊事件 -->
<button @click="reverseArr">reverse</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
arr: ['loki', 'andy', 'thor']
},
methods: {
reverseArr() {
this.arr.unshift('messy');
}
}
})
</script>
</body>
...
當我們不給定key值或者將key值給爲index, 我們觀察會發現, 在控制檯中的Elements中查看dom元素的時候, 我們僅僅只是增加一個人名, 但是四個li的dom元素都進行了重新渲染,
而我們如果將key值改爲一個唯一值,情況則不一樣
...
<!-- 下方的key值經過拼接在這個案例中是唯一的, 一般的開發中後端會返回id過來 -->
<li v-for="(ele, index) in arr" :key="`${ele}_${index}`">{{ ele }}</li>
...
我們發現只有新增的dom被重新渲染了, 其他dom都沒有變化, 這樣對性能的消耗大大降低
所以說這個key值我們必須給, 還得是唯一值, 因爲他會幫我們儘可能的減少dom的操作
v-if, v-else-if, v-else
與JavaScript的條件語句 if
, else
, else if
邏輯相似, Vuejs的條件指令可以根據表達式的值在dom中渲染或者銷燬元素/組件
在過去中, 如果我們想通過某個屬性控制dom元素的存在與否(注意: 不是顯示與否), 我們大概率會通過如下操作
(function() {
const div = document.querySelector('.wrapper');
const btn = document.querySelector('.btn');
let flag = true;
btn.onclick = function() {
flag = !flag;
if(flag) div.innerHTML = '<span>你好, 我是loki</span>';
else div.innerHTML = '<p>你好, 我是thor</p>'
}
}())
這樣我們就基本控制了一個元素的銷燬與否, flag爲true的時候p元素是完全被銷燬狀態的, 不存在與dom結構中
而Vue幫助我們實現同樣的功能, 衍生出了v-if, v-else, v-else-if
...
<body>
<div id='#app'>
<div class='wrapper'>
<span v-if="flag">你好, 我是loki</span>
<p v-else>你好, 我是thor</p>
</div>
<button @click='changeStatus' class='.btn'>Click Me</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
flag: true
},
methods: {
changeStatus() {
this.flag = !this.flag;
}
}
})
</script>
</body>
...
注意: v-if
和v-else
, v-else-if
必須是兄弟元素緊緊地帖在一起, 就他們中不允許有第三者或者第四者插足, 像下方這種情況就會報錯
<div id='app'>
<p v-if='flag'>你好</p>
<span>hello</span>
<p v-else>我叫loki</p>
</div>
v-show
上面的v-if我們說是讓一個元素永久的銷燬或者存在的, 而假如我們有一個元素是需要經常的切換顯示隱藏的, 我們可能就不是很想用v-if了, 因爲v-if引發的重排對性能消耗是挺大的, 我們是否有一種讓元素隱藏的方案呢, 當然有, 那就是v-show
v-show用法與v-if基本一致, 只是當使用了v-show來控制元素顯示與否的話, 等於給鈣元素設置display:none 和block一樣, 同時該元素綁定的事件仍然可以觸發
v-once
假如我們有一個需求是讓一個元素的內容只在第一次渲染, 後面無論數據怎麼產生變化, 頁面都不會再進行渲染和變更了, 那麼這個時候我們可以用到v-once
v-model
我們知道MVVM模式的核心是雙向數據綁定, 而Vue在這種模式下提出了v-model指令, 我們一起來看看這哥們的神通
我們現在有一個需求要實現的功能如下
上方的功能其實已經稱之爲雙向數據綁定了, 當我們在操控視圖(不斷在輸入框鍵入值的時候, 後臺的數據會變化, 同時後臺的數據產生變化影響了下方的文字顯示產生變化)
就如上方的功能我們如果用原生js寫應該怎麼寫呢? 大家也可以思考思考
(function() {
// 頁面中有一個input框, 和一個class爲'input-value'的span標籤
// 原生js
const input = document.querySelector('input');
const showValue = document.querySelector('.input-value');
input.oninput = function(e) {
let resultValue = e.target.value; // 拿到input的值
showValue.innerText = resultValue;
}
}())
用Vue的話其實簡單很多
...
<body>
<div class="wrapper">
<input v-model='inputValue' type="text" name="" id="" />
<p>您當前寫入的值:<span class="input-value">{{ inputValue }}</span></p>
</div>
<script>
const vm = new Vue({
el: '.wrapper',
data: {
inputValue: ''
}
})
</script>
</body>
..
在input上加的一個v-model解決所有難題
你可以把v-model可以放在任何你想要監控的表單控件上, 一旦添加了v-model, 則表單變爲受控組件
實際上,v-model其實是一個語法糖, 它的本來面目其實就是這樣的
...
<body>
<div class="wrapper">
<!-- @input是一個事件, 跟oninput功能完全一樣, 先混個臉熟 -->
<input :value='inputValue' @input='changeValue' type="text" name="" id="" />
<p>您當前寫入的值:<span class="input-value">{{ inputValue }}</span></p>
</div>
<script>
const vm = new Vue({
el: '.wrapper',
data: {
inputValue: ''
},
methods: {
changeValue(e) {
this.inputValue = e.target.value;
}
}
})
</script>
</body>
..
修飾符, 在v-model中也給我們提供了一些修飾符, 至於修飾符是什麼, 在稍後的事件板塊我會詳細介紹, 這裏等同於混個臉熟, 等看完事件再來回過頭來看看這兒, 會有不同的新收穫
-
.lazy: v-model默認是@input和value的語法糖, 也就是我們沒鍵入一次value都會產生響應的改變, 而我們設置爲lazy以後, v-model就成了@change和value的語法糖了, 必須等到輸入框失去焦點或者按下回車value值纔會進行更改
-
.trim: 自動消除綁定值的前後空格
-
.number: 會將輸入轉換爲Number類型, 因爲我們知道, 我們從input框提取出來的value值其實是String類型, 加上這個修飾符我們可以直接提取到Number類型的值
<!-- 可以連着寫 -->
<input v-model.lazy.trim='inputValue' />
v-on
在原生js中, 相信大家都給dom元素綁定過事件, 我們通常是如下操作
const div = document.querySelector('div');
div.onclick = function() {
console.log('hello');
}
div.addEventListener('mouseover', function(){
console.log('change')
}, false)
由於在Vue中我們暫時無法獲得dom元素, 實際上如果直接操控dom, 那麼我們用不用Vue都無所謂了, 所以Vue跟其他指令一樣, 給我們提供了一個v-on指令, 直接寫在被Vue實例接管區域內的dom元素上
...
<body>
<div id="app">
<div class='box' v-on:click = 'handleClick'>xxx</div>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
handleClick() {
console.log('hello');
}
}
})
</script>
</body>
...
而同時, 跟v-bind一樣, v-on也提供一個語法糖
我們可以使用@
來代替v-on:
<div class='box' @click = 'handleClick'>xxx</div>
關於事件源對象e
大家可能會關心事件源對象e, 其實不用擔心, 事件源對象Vue也會完好無損的通過第一個參數來傳遞給我們(前提是我們沒有自己傳參),如果我們自己傳了參, Vue則會通過$event
來傳遞給我們
...
<body>
<div id="app">
// 注意在這裏需要手動傳入$event
<div class='box' v-on:click = 'handleClick' @mouseover='handleOver($event,"loki")'>xxx</div>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
handleClick(e) {
console.log(e);
},
handleOver(name, $event) {
console.log($event, name)
}
}
})
</script>
</body>
...
至於事件, 五花八門的, 比如click, mouseover, mouseenter好多包括自定義事件, 稍後會在事件專欄中好好寫寫,
自定義指令
Vue在提供給我們內置指令的同時, 也允許我們自己註冊自定義指令進行擴展, 這些自定義指令會在某些特殊場景中產生奇效
自定義指令我明天再寫, 今天累了