Vue2 实战进阶:表单数据收集、指令系统与自定义指令全解析

在前几篇文章中,我们学习了Vue的核心概念和常用指令。今天我们将深入探讨Vue的表单数据收集 、完整的指令系统 以及自定义指令的创建与使用。这些内容是日常开发中最常用的技能。

一、表单数据收集

1.1 基础表单绑定

Vue提供了 v-model 指令来实现表单元素的双向数据绑定。结合修饰符,我们可以轻松处理各种表单场景。

复制代码
<form @submit.prevent="sendMsg">
    <!-- 自动去除首尾空格 -->
    <input v-model.trim="userInfo.name">
    
    <!-- 自动转换为数字类型 -->
    <input v-model.number="userInfo.age">
    
    <!-- 失焦后更新数据(懒加载) -->
    <textarea v-model.lazy="userInfo.area"></textarea>
</form>

v-model 常用修饰符:

修饰符 功能 说明
.trim 自动去除首尾空格 适用于文本输入
.number 自动将输入转为数字类型 适用于数字输入
.lazy 在 change 事件后更新(失焦时) 减少实时更新频率

1.2 不同表单元素的数据收集

不同类型的表单元素,其数据格式和绑定方式有所不同:

元素类型 数据格式 示例
文本框 字符串 <input v-model="name">
单选框 字符串 <input type="radio" v-model="gender" value="男">
复选框 数组 <input type="checkbox" v-model="hobbies" value="篮球">
下拉框 字符串 <select v-model="city"><option value="北京">北京</option></select>
协议框 布尔值 <input type="checkbox" v-model="agreed">

完整示例:

复制代码
<form @submit.prevent="sendMsg">
    <!-- 文本框 -->
    姓名:<input v-model.trim="userInfo.name"><br>
    
    <!-- 数字输入 -->
    年龄:<input v-model.number="userInfo.age" type="number"><br>
    
    <!-- 单选框 -->
    性别:
    <input type="radio" v-model="userInfo.gender" value="男">男
    <input type="radio" v-model="userInfo.gender" value="女">女<br>
    
    <!-- 复选框(数组) -->
    爱好:
    <input type="checkbox" v-model="userInfo.hobbies" value="篮球">篮球
    <input type="checkbox" v-model="userInfo.hobbies" value="足球">足球
    <input type="checkbox" v-model="userInfo.hobbies" value="乒乓球">乒乓球<br>
    
    <!-- 下拉框 -->
    城市:
    <select v-model="userInfo.city">
        <option value="">请选择城市</option>
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="广州">广州</option>
    </select><br>
    
    <!-- 协议框(布尔值) -->
    <input type="checkbox" v-model="userInfo.agreed">同意用户协议<br>
    
    <button type="submit">提交</button>
</form>

1.3 数据提交处理

复制代码
methods: {
    sendMsg() {
        // 将JS对象转为JSON格式,便于后端处理
        console.log(JSON.stringify(this.userInfo));
        
        // 发送到后端
        // axios.post('/api/submit', this.userInfo).then(...)
    }
}

二、Vue指令系统

2.1 内容渲染指令

Vue提供了三种内容渲染方式,各有特点和适用场景。

v-text 指令

将内容填充到标签体中,以覆盖的形式填充。即使内容中包含HTML标签,也只会当作普通字符串处理,不会解析。

复制代码
<!-- 功能等同于 innerText -->
<div v-text="name"></div>

<!-- 等价于 -->
<div>{{ name }}</div>
v-html 指令

将内容填充到标签体中,以覆盖的形式填充,并且会将内容中的HTML标签进行解析。

复制代码
<!-- 功能等同于 innerHTML -->
<div v-html="htmlContent"></div>

⚠️ 安全警告 :v-html 不要用在用户提交的内容上,可能导致XSS攻击。

XSS攻击示例:

复制代码
<!-- 用户留言中恶意植入以下代码 -->
<script>alert('恶意代码')</script>

指令对比:

指令 功能 特点
v-text 文本渲染 覆盖内容,不解析HTML
v-html HTML渲染 解析并执行HTML代码
{``{ }} 插值表达式 灵活的内容绑定,不覆盖

2.2 特殊指令

v-pre 指令

跳过该元素及其子元素的编译过程,提高编译效率,避免不必要的编译。

复制代码
<!-- 不会编译,直接显示原始内容 -->
<div v-pre>{{ 这里的内容不会被编译 }}</div>
v-once 指令

只渲染元素和组件一次,后续视为静态内容,跳过更新。

复制代码
<!-- 只渲染一次,后续num变化不再更新 -->
<div v-once>{{ num }}</div>
v-cloak 指令

解决页面闪烁问题(未编译模板显示问题),需配合CSS使用。

复制代码
/* CSS中定义 */
[v-cloak] {
    display: none;
}

<!-- HTML中使用 -->
<div v-cloak>{{ message }}</div>

三、XSS安全防护

3.1 潜在风险示例

复制代码
<!-- 恶意代码可能通过用户输入注入 -->
<li v-for="item in myList" v-html="item"></li>

3.2 防护措施

  1. 避免直接使用 v-html 渲染用户输入

  2. 对用户输入进行过滤和转义

  3. 使用 v-text 替代 v-html 显示纯文本

    // 对用户输入进行转义
    function escapeHtml(text) {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode(text));
    return div.innerHTML;
    }

四、自定义指令

当Vue内置指令无法满足需求时,我们可以创建自定义指令。

4.1 局部自定义指令

在组件的 directives 选项中定义,仅在该组件中可用。

复制代码
directives: {
    // 简写形式(在bind和update时触发)
    'text-danger': function(element, binding) {
        element.innerHTML = binding.value;
        element.style.color = 'red';
    },
    
    // 完整写法
    focus: {
        // 指令第一次绑定到元素时调用
        bind(el, binding) {
            // 初始化工作
        },
        // 元素插入父节点时调用
        inserted(el) {
            el.focus();
        },
        // 所在组件更新时调用
        update(el, binding) {
            // 更新处理
        }
    }
}

4.2 全局自定义指令

通过 Vue.directive() 注册,在整个应用中都可使用。

复制代码
// 全局注册
Vue.directive('bind-blue', {
    // 指令绑定到元素时
    bind: function(element, binding) {
        element.value = binding.value;
    },
    // 元素插入父节点时
    inserted: function(element, binding) {
        element.parentNode.style.backgroundColor = 'blue';
    }
});

4.3 指令钩子函数

钩子函数 调用时机
bind 指令第一次绑定到元素时
inserted 元素插入父节点时
update 所在组件更新时
componentUpdated 组件及其子组件全部更新后
unbind 指令与元素解绑时

4.4 钩子函数参数

指令钩子函数接收以下参数:

  • el:指令所绑定的元素,可直接操作DOM
  • binding:一个对象,包含以下属性:
    • name:指令名,不含 v- 前缀
    • value:指令的绑定值
    • oldValue:指令绑定的前一个值(仅在 update 和 componentUpdated 中可用)
    • expression:绑定值的字符串形式
    • arg:传给指令的参数
    • modifiers:包含修饰符的对象

示例:

复制代码
<div v-demo:foo.a.b="message"></div>

Vue.directive('demo', {
    bind(el, binding) {
        console.log(binding.name);      // 'demo'
        console.log(binding.value);     // message的值
        console.log(binding.expression); // 'message'
        console.log(binding.arg);       // 'foo'
        console.log(binding.modifiers); // { a: true, b: true }
    }
});

总结

今天我们学习了以下内容:

表单处理

  • 合理使用 .trim、.number、.lazy 修饰符
  • 根据表单元素类型选择合适的数据格式
  • 提交时使用 JSON.stringify 转换为JSON格式

内容渲染

  • 纯文本显示使用 v-text 或 {``{ }}
  • 需要解析HTML时使用 v-html,但要警惕XSS攻击
  • 优先使用 v-text 替代 v-html 显示用户输入

性能优化

  • 使用 v-pre 跳过不需要编译的区域
  • 使用 v-once 标记静态内容,减少更新开销
  • 使用 v-cloak 解决页面闪烁问题

安全防护

  • 警惕XSS攻击,谨慎使用 v-html
  • 对用户输入进行过滤和转义
  • 避免在 v-html 中渲染用户提交的内容

代码复用

  • 通过自定义指令封装常用功能
  • 全局指令适用于通用功能,局部指令适用于组件特定功能
  • 合理使用指令钩子函数,在合适的时机操作DOM

掌握了表单数据收集、指令系统和自定义指令,你的Vue开发能力已经相当全面了。

相关推荐
福兮说15 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea15 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨16 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
niucloud-admin16 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强16 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
今年下半年18 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理18 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
前端snow20 小时前
ai agent --- DeepAgents 中间件
前端
data analyse 45620 小时前
报表能自定义的国内统计工具有哪些
前端·数据分析