vue实现检测敏感词过滤组件的多种思路

目录
  • 写在前面
  • 需求分析v1
  • 思路一:使用截流方法监听输入框的input事件
  • 思路二:使用输入框的失焦和保存按钮的点击事件
  • 思路三:使用mixins抽取敏感词检测方法
  • 思路四:使用promise封装敏感词检测组件(面向需求v1)
  • 思路五:使用插槽和mixins封装敏感词检测组件(面向需求v2)
  • 优化与改进
  • 写在最后

写在前面

  在做商户端敏感词检测的过程中,发现了一些问题,特在此总结。本文的行文思路是编写敏感词检测代码,前两个思路未采用组件化的开发思想,后三个思路根据需求变更,采用组件化的思想和mixins混入进行开发。

需求分析v1

在商户端产品模块,点击产品编辑按钮,可以修改产品的标题和价格。当没有填写产品标题时,置灰保存按钮;当填写的产品标题属于敏感词时,置灰保存按钮并给出后端返回的提示。

在商户端定制模块,定制完成后,直接跳转到产品编辑页面,可以修改产品标题和价格。当没有填写产品标题时,置灰保存按钮;当填写的产品标题属于敏感词时,置灰保存按钮并给出后端返回的提示。

思路一:使用截流方法监听输入框的input事件

  因为本人负责的是产品模块,不知道定制模块的产品标题也需要增加敏感词检测,所以最开始并没有将敏感词检测写成组件。于是有了第一种思路:使用截流方法监听输入框的input事件。

  思路:

  1.只要输入不为空或者全是空格,每次输入后都会触发输入框的input事件,调用敏感词检测接口。频繁地请求接口会给服务器造成巨大的压力,因此可以使用截流方法降低接口请求的频率;

  2.为请求的接口增加一个定时器,并添加一个倒计时间,记为1s,每次输入后都延迟1s请求接口。于是可以在输入框的input事件触发后,清除掉上一个定时器。防止定时器叠加,重复请求多次接口,只保留最后一次input事件触发的敏感词检测的接口请求。这也就意味着,如果用户连续输入产品标题,且每次输入的间隔时间小于1s,则用户最后一次输入的信息会被接口检测是否合乎敏感词规范;如果用户间隔着输入产品标题,且间隔时间都超过1s,则会发起多次接口请求,还是会对服务器造成不小的压力,所以这种方法还是存在局限性。

//敏感词检测的html
<div class="edit-title">产品标题</div>
   <el-input
     v-model="productName"
     placeholder="请输入产品标题"
     type="text"
     auto-complete="on"
     clearable
     @input="inspectSpams"
   />
<div v-if="showMessage" class="message">{{ errorMessage }}</div>

//保存按钮的html
<el-button type="primary" @click="save" :disabled="productName === '' || showMessage === true">保存</el-button>
 data() {
    return {
      productName: '',
      errorMessage: '',
      showMessage: false,
      timer: -1
    }
  },
  methods: {
    inspect() {
      if(this.productName.trim() !== '') {
        this.$store.dispatch('products/inspectSpams', this.productName).catch((err)=>{
          this.errorMessage = err.response.data.message
          this.showMessage = true
        })
      }
    },
    inspectSpams() {
      this.showMessage = false
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.inspect()
      }, 1000)
    }
  }

  缺陷: 当为产品标题添加敏感词后,只要手速足够快,在1s内点击保存按钮,还是可以成功保存敏感词,这与我们的需求相违背。

思路二:使用输入框的失焦和保存按钮的点击事件

  既然使用输入框的input事件存在问题,那是否能够使用输入框的失焦事件和保存按钮的点击事件呢?答案是可以的。只不过在这个过程中,有两个问题需要特别注意。

注意事项:

  • 需要理解失焦事件。 何为失焦?在输入框内输入完标题之后,点击输入框外的任意地方都会触发失焦事件。所以,千万不要忘记点击保存按钮同样会触发失焦事件。因此,只需要在输入框失焦事件中请求敏感词检测接口,无需在点击事件中重复请求。
  • 需要考虑触发失焦事件和点击事件带来的的异步问题。 点击保存按钮会同时触发失焦事件和点击事件,失焦事件会优先点击事件执行。失焦事件用于请求敏感词检测接口,点击事件用于修改产品信息。交互逻辑是先请求敏感词检测接口,如果接口返回的状态是成功,则不需要显示错误提示信息;否则需要显示后端返回的错误信息,并禁用保存按钮。待校验成功之后再请求修改产品信息的接口。因此,这两个方法是存在一个先后顺序的。而且一定是失焦事件请求敏感词接口在前,请求修改产品信息在敏感词接口请求结束之后。不能因为敏感词检测过慢导致非法的敏感词已经成功保存并渲染,此时再请求敏感词检测接口是没必要的。由于无法确定和保证两个接口的,所以需要增加一个变量来判断敏感词接口是否请求结束。如果接口没有请求结束,需要在点击事件中重新发起请求;如果接口已经完成请求,则直接return忽略掉。

思路:

  • 为输入框添加失焦事件;
  • 为保存按钮添加点击事件。

代码:

<div class="edit-title">产品标题</div>
 <el-input
   v-model="productName"
   placeholder="请输入产品标题"
   type="text"
   auto-complete="on"
   clearable
   @blur="inspectSpams"
 />
 <div v-if="showMessage" class="message">{{ errorMessage }}</div>

 <el-button type="primary" @click="save" :disabled="!productName || showMessage">保存</el-button>
 data() {
   return {
     showMessage: false,
     productName: '',
     errorMessage: '',
     timer: -1,
     hasVerified: false
   }
 },
 methods: {
  //失焦事件(请求敏感词检测接口)
   async inspectSpams() {
     this.hasVerified = false
     this.showMessage = false
     if(this.productName.trim() !== '') {
       await this.$store.dispatch('products/inspectSpams', this.productName).catch((err) => {
         this.errorMessage = err.response.data.message
         this.showMessage = true
       })
     }
     this.hasVerified = true
   },
   //点击事件(请求修改产品信息接口)
   async save() {
     if(!this.hasVerified) {
        await this.inspectSpams()
     }
     const variants = this.variants.map((variant) => {
       return {
         id: variant.id,
         price: variant.price,
       }
     })
     const params = {
       variants,
       name: this.productName
     }
     params.productId = this.productId
     await this.$store.dispatch('products/editProduct', params)
       .then(async() => {
         await this.getProductListData(this.productStatus, 1)
         this.$message({
           type: 'success',
           message: '产品修改成功!'
         })
       })
       .catch((message) => {
         this.$message({
           type: 'error',
           message
         })
       })
     this.showEditProductDialog = false
   }
 }

思路三:使用mixins抽取敏感词检测方法

  本以为敏感词检测就这样离我而去了,结果收到产品消息,同样需要给定制模块的产品标题增添敏感词检测。之后就是一顿ctrl+c和ctrl+v操作猛如虎,最后发现代码冗余过多,需要对代码进行整理。此处和后续都只写产品模块的敏感词检测逻辑,定制模块的敏感词检测逻辑其实和产品模块大同小异。 既然定制模块的产品标题编辑和产品模块的样式和逻辑相差无几,那何不抽取敏感词检测公共方法呢?就这么愉快地决定了,键盘上一顿狂敲乱打后,混入方法就成型了:

export default {
data() {
     return {
         hasVerified: false,
         showMessage: false,
         errorMessage: ''
     }
 },
 methods: {
     async inspectSpams(name) {
         this.hasVerified = false
         this.showMessage = false
         if(name.trim() !== '') {
           await this.$store.dispatch('products/inspectSpams', name).catch((err) => {
             this.errorMessage = err.response.data.message
             this.showMessage = true
           })
         }
         this.hasVerified = true
     }
 }
}
<div class="edit-title">产品标题</div>
<el-input
    v-model="productName"
    placeholder="请输入产品标题"
    type="text"
    auto-complete="on"
    clearable
    @blur="inspectSpams(productName)"
/>
<div v-if="showMessage" class="message">{{ errorMessage }}</div>

<el-button type="primary" @click="save" :disabled="!productName ||  showMessage">保存</el-button>
import inspectSpams from '@/mixins/inspectSpams'

export default {
     data() {
          return {
              productName: ''
          }
      },
      mixins: [ inspectSpams ],
      methods: {
        //点击事件(请求修改产品信息接口)
        async save() {
          if(!this.hasVerified) {
              await this.inspectSpams(this.productName)
          }
          const variants = this.variants.map((variant) => {
            return {
              id: variant.id,
              price: variant.price,
            }
          })
          const params = {
            variants,
            name: this.productName
          }
          params.productId = this.productId
          await this.$store.dispatch('products/editProduct', params)
            .then(async() => {
              await this.getProductListData(this.productStatus, 1)
              this.$message({
                type: 'success',
                message: '产品修改成功!'
              })
            })
            .catch((message) => {
              this.$message({
                type: 'error',
                message
              })
            })
          this.showEditProductDialog = false
        }
      }
}

思路四:使用promise封装敏感词检测组件(面向需求v1)

  考虑到产品模块敏感词检测和定制模块的html结构相差无几,决定封装一个敏感词检测组件,将产品标题敏感词检测的html代码和业务逻辑放在一起。但在这个过程中,有三个问题需要特别注意:

注意事项:

  • async函数返回的是一个promise对象;
  • 不能直接修改传入的props值,但是可以通过中间变量,将中间变量和props双向绑定,从而间接地修改props的值;
  • 可以在父组件给props增加sync修饰符,在子组件中对props和中间变量进行监听。如果任意一方的值发生变化,都会将改变后的值赋予给另一方,从而达到双向绑定的目的。

思路:

  • 编写敏感词检测组件;
  • 引入敏感词检测组件。
//敏感词检测组件
<template>
    <div>
        <el-input v-model="input" placeholder="请输入产品标题" type="text" clearable @blur="inspectSpams" />
        <div v-if="isShowMessage" class="message">{{ errorMessage }}</div>
    </div>
</template>

<script>
export default {
    props: {
        title: {
            required: true,
            type: String
        }
    },
    data() {
        return {
            input: '',
            isShowMessage: false,
            errorMessage: '',
            hasVerified: true
        }
    },
    watch: {
        title: {
            handler(val) {
                this.input = val
            },
            immediate: true
        },
        input(val) {
            this.$emit('update:title', val)
        }
    },
    methods: {
        async inspectSpams() {
            this.hasVerified = false
            this.isShowMessage = false
            if (this.input !== '') {
                await this.$store.dispatch('products/inspectSpams', this.input).catch((err) => {
                    this.errorMessage = err.response.data.message
                    this.isShowMessage = true
                })
            }
            this.hasVerified = true
        },
        init() {
            this.isShowMessage = false
        },
        async verify() {
            if (!this.hasVerified) {
                await this.inspectSpams()
            }
            const emptyInput = this.input.trim()
            if (emptyInput === '') {
                this.isShowMessage = true
                this.errorMessage = '请输入产品名称'
            }
            return new Promise((resvole, reject) => {
                if (Boolean(!emptyInput || this.isShowMessage)) {
                    reject()
                } else {
                    resvole()
                }
            })
        }
    }
}
</script>

<style>
.message {
    font-weight: bold;
    color: red;
    margin-top: 10px;
}
</style>
//引入敏感词检测组件
<script>
import { mapState } from 'vuex'
import InspectSpams from  '@/components/InspectSpams'

export default {
 name: 'List',
 components: {
   InspectSpams
 },
 data() {
   return {
     productName: ''
   }
 },
 computed: {
   ...mapState({
     variants: (state) => state.products.detail.variants
   }),
 },
 methods: {
   save() {
     this.$refs.productSpamsRef.verify()
       .then(async()=>{
         const variants = this.variants.map((variant) => {
         return {
           id: variant.id,
           price: variant.price,
         }
       })
       const params = {
         variants,
         name: this.productName
       }
       params.productId = this.productId
       await this.$store.dispatch('products/editProduct', params)
         .then(async() => {
           await this.getProductListData(this.productStatus, 1)
           this.$message({
             type: 'success',
             message: '产品修改成功!'
           })
         })
       this.showEditProductDialog = false
       })
       .catch(()=>{
         this.$message({
           type: 'error',
           message: '请输入合法的产品名称'
         })
       })
   },
   getProductListData(status, page) {
     this.$store.dispatch('products/getList', {
       limit: 16,
       status,
       order: 'id',
       direction: 'desc',
       page
     })
   }
}
</script>

<template>
    <div>
      <div class="edit-title">产品标题</div>
      <InspectSpams
         :title.sync="productName"
         ref="productSpamsRef"
      />
      <el-button type="primary" @click="save">保存</el-button>
    </div>
</template>

思路五:使用插槽和mixins封装敏感词检测组件(面向需求v2)

  需求变更: 其实相比需求v1来说,也没发生什么变化。只是产品模块的产品标题必须得填写,不然得禁止保存按钮,而定制模块的产品标题可以不填写,保存后默认为填写的产品标题 + 白板名称。

  思路: 既然如此,何不把给错误提示的html放入一个组件中,使用插槽占位表示需要检测的字段,而将敏感词检测的逻辑放到mixins中。后续如果还有其它地方需要进行敏感词检测,会显得更加灵活,其实这样反倒更利于组件的复用原则。

//敏感词检测组件
<template>
 <div>
     <slot />
     <div v-if="isShowMessage" class="message">
         {{ errorMessage }}
     </div>
 </div>
</template>

<script>
export default {
 props: {
     isShowMessage: {
         required: true,
         type: Boolean
     },
     errorMessage: {
         required: true,
         type: String
     }
 }
}
</script>

<style>
.message {
 font-weight: bold;
 color: red;
 margin-top: 10px;
}
</style>
//敏感词检测的mixins
export default {
 data() {
     return {
         isShowMessage: false,
         errorMessage: '',
         hasVerified: true
     }
 },
 methods: {
     async inspectSpams(name) {
         this.hasVerified = false
         this.isShowMessage = false
         if (name.trim() !== '') {
             await this.$store.dispatch('products/inspectSpams', name).catch((err) => {
                 this.errorMessage = err.response.data.message
                 this.isShowMessage = true
             })
         }
         this.hasVerified = true
     }
 }
}
import InspectSpams from  '@/components/InspectSpams'
import inspectSpams from '@/mixins/inspectSpams'

components: {
 InspectSpams
},
mixins: [ inspectSpams ],

async save() {
   if(!this.hasVerified) {
     await this.inspectSpams(this.productName)
   }
   const variants = this.variants.map((variant) => {
     return {
       id: variant.id,
       price: variant.price,
     }
   })
   const params = {
     variants,
     name: this.productName
   }
   params.productId = this.productId
   await this.$store.dispatch('products/editProduct', params)
     .then(async() => {
       await this.getProductListData(this.productStatus, 1)
       this.$message({
         type: 'success',
         message: '产品修改成功!'
       })
     })
     .catch((message) => {
       this.$message({
         type: 'error',
         message
       })
     })
   this.showEditProductDialog = false
 },

<div class="edit-title">产品标题</div>
<InspectSpams :isShowMessage="isShowMessage" :errorMessage="errorMessage">
 <el-input
     v-model="productName"
     placeholder="请输入产品标题"
     type="text"
     auto-complete="on"
     clearable
     @blur="inspectSpams(productName)"
 />
</InspectSpams>

优化与改进

  1.优化调用敏感词检测的条件。如果产品标题没有发生变化,则不需要再请求敏感词检测接口。因为只有经过检验成功的标题才能被成功保存,所以无需多次重复调用接口,需要修改mixins请求接口的条件。

  思路: 在根据产品id打开模态框请求产品详情接口的过程中,将对应产品信息的name字段赋值给新增的originalName变量。在html和js调用混入方法inspectSpams的过程中,将originalName和productName作为变量传入即可。

//修改后的mixins混入
export default {
    data() {
        return {
            isShowMessage: false,
            errorMessage: '',
            hasVerified: true
        }
    },
    methods: {
        async inspectSpams(originalName, currentName) {
            this.hasVerified = false
            this.isShowMessage = false
            if (originalName !== currentName && currentName.trim() !== '') {
                await this.$store.dispatch('products/inspectSpams', currentName).catch((err) => {
                    this.errorMessage = err.response.data.message
                    this.isShowMessage = true
                })
            }
            this.hasVerified = true
        }
    }
}

  2.多次点击按钮会重复请求接口。可以使用防抖、按钮启用倒计时、封装axios请求、给button设置loading等方式进行优化。

写在最后

  其实总结得不是很好,编写的组件也不够好,思路也不太清晰,记录在这里主要是对思路二和思路四做个总结,毕竟对vue的文档还是不太熟悉。在敏感词检测组件中,其实还有很多可以改进的地方,欢迎大家在评论区中指出。

以上就是vue编写检测敏感词汇组件的多种思路的详细内容,更多关于vue编写检测敏感词汇组件的资料请关注我们其它相关文章!

(0)

相关推荐

  • laravel框架实现敏感词汇过滤功能示例

    本文实例讲述了laravel框架实现敏感词汇过滤功能.分享给大家供大家参考,具体如下: 最近项目有需求,要对用户的签名,回复进行敏感词检测,然后搜到了一个好用的扩展,分享给大家. https://github.com/FireLustre/php-dfa-sensitive 通过 composer 进行安装: composer require lustre/php-dfa-sensitive 然后在 app 目录下创建 Services ,并添加 SensitiveWords.php <?php

  • 浅谈Python 敏感词过滤的实现

    一个简单的实现 class NaiveFilter(): '''Filter Messages from keywords very simple filter implementation >>> f = NaiveFilter() >>> f.add("sexy") >>> f.filter("hello sexy baby") hello **** baby ''' def __init__(self):

  • Python实现敏感词过滤的4种方法

    在我们生活中的一些场合经常会有一些不该出现的敏感词,我们通常会使用*去屏蔽它,例如:尼玛 -> **,一些骂人的敏感词和一些政治敏感词都不应该出现在一些公共场合中,这个时候我们就需要一定的手段去屏蔽这些敏感词.下面我来介绍一些简单版本的敏感词屏蔽的方法. (我已经尽量把脏话做成图片的形式了,要不然文章发不出去) 方法一:replace过滤 replace就是最简单的字符串替换,当一串字符串中有可能会出现的敏感词时,我们直接使用相应的replace方法用*替换出敏感词即可. 缺点: 文本和敏感词少

  • python 实现敏感词过滤的方法

    如下所示: #!/usr/bin/python2.6 # -*- coding: utf-8 -*- import time class Node(object): def __init__(self): self.children = None # The encode of word is UTF-8 def add_word(root,word): node = root for i in range(len(word)): if node.children == None: node.c

  • Python 实现王者荣耀中的敏感词过滤示例

    王者荣耀的火爆就不用说了,但是一局中总会有那么几个挂机的,总能看到有些人在骂人,我们发现,当你输入一些常见的辱骂性词汇时,系统会自动将该词变成"*",作为python初学者,就想用python来实现这一功能. 步骤很简单所以就用交互式演示 首先我们要知道王者荣耀有哪些敏感词汇,然后放到一个元组, 第二步用户接收输入的消息 第三步处理敏感词汇 最后输出处理后的消息. >>> words=('金币', '挂', '傻逼', '猪', '你妈') #创建一个敏感词汇库 &g

  • js实现敏感词过滤算法及实现逻辑

    最近弄了一个用户发表评论的功能,用户上传了评论,再文章下可以看到自己的评论,但作为社会主义接班人,践行社会主义核心价值观,所以给评论敏感词过滤的功能不可少,在网上找了资料,发现已经有非常成熟的解决方案. 常用的方案用这么两种 1.全文搜索,逐个匹配.这种听起来就不够高大上,在数据量大的情况下,会有效率问题,文末有比较 2.DFA算法-确定有限状态自动机 附上百科链接确定有限状态自动机 DFA算法介绍 DFA是一种计算模型,数据源是一个有限个集合,通过当前状态和事件来确定下一个状态,即 状态+事件

  • python用类实现文章敏感词的过滤方法示例

    过滤一遍并将敏感词替换之后剩余字符串中新组成了敏感词语,这种情况就要用递归来解决,直到过滤替换之后的结果和过滤之前一样时才算结束 第一步:建立一个敏感词库(.txt文本) 第二步:编写代码在文章中过滤敏感词(递归实现) # -*- coding: utf-8 -*- # author 代序春秋 import os import chardet # 获取文件目录和绝对路径 curr_dir = os.path.dirname(os.path.abspath(__file__)) # os.path

  • 利用Python正则表达式过滤敏感词的方法

    问题描述:很多网站会对用户发帖内容进行一定的检查,并自动把敏感词修改为特定的字符. 技术要点: 1)Python正则表达式模块re的sub()函数: 2)在正则表达式语法中,竖线"|"表示二选一或多选一. 参考代码: 以上这篇利用Python正则表达式过滤敏感词的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • Java实现DFA算法对敏感词、广告词过滤功能示例

    一.前言 开发中经常要处理用户一些文字的提交,所以涉及到了敏感词过滤的功能,参考资料中DFA有穷状态机算法的实现,创建有向图.完成了对敏感词.广告词的过滤,而且效率较好,所以分享一下. 具体实现: 1.匹配大小写过滤  2.匹配全角半角过滤  3.匹配过滤停顿词过滤.  4.敏感词重复词过滤. 例如: 支持如下类型类型过滤检测: fuck 全小写 FuCk 大小写 fuck全角半角 f!!!u&c ###k 停顿词 fffuuuucccckkk 重复词 敏感词过滤的做法有很多,我简单描述我现在理

  • PHP实现的敏感词过滤方法示例

    本文实例讲述了PHP实现的敏感词过滤方法.分享给大家供大家参考,具体如下: 1.敏感词过滤方法 /** * @todo 敏感词过滤,返回结果 * @param array $list 定义敏感词一维数组 * @param string $string 要过滤的内容 * @return string $log 处理结果 */ function sensitive($list, $string){ $count = 0; //违规词的个数 $sensitiveWord = ''; //违规词 $st

  • 基于python实现检索标记敏感词并输出

    一些带有过度宣传的词,在淘宝.京东对商品的宣传有一定的限制,这些最佳,最大.盗版.水货等词语都不能用于产品的宣传,可以使用程序检测敏感词,以下既是具体代码. #检索敏感词并描红输出 #输入 word = input("请输入或拷贝含有敏感词的宣传文字:") #敏感词库 sensitive = ['第一','国家级','最高级','最佳','独一无二','一流','仅此一次','顶级',\ '顶尖','尖端','极品','极佳','绝佳','绝对','终极','极致','首个','首选'

随机推荐