一 效果图

二 组件封装步骤

1 组件目录结构如下

2 组件是需要一个密码输入框和一个pop 框,在input获取焦点的时候展示popover,popover 中的每一项都要根据输入内容实时匹配是否满足某一规则,因此里面的内容需要动态渲染,如下结构

<template><el-popover popper-class="gt-password-popper" v-bind="popoverOptions"><template slot="reference"><el-inputclass="gt-password"v-bind="$attrs"v-on="$listeners":type="passwordType ? 'password' : 'text'"><i@click="triggerPassword"slot="suffix":class="['trigger-password', passwordType ? '' : 'show']"></i></el-input></template><CheckList:pagek="pagek":values.sync="checkValuesObj":title="$t('Basic.Password_must_include')":options="checkList"/></el-popover>
</template><script lang="ts">
import { Component, Prop, Vue, Watch, Computed } from "vue-property-decorator";
import CheckList from "./CheckList.vue";
import { ruleItem } from "./index.type";const popDefault = {placement: "right-start",width: 228,trigger: "focus"
};@Component({components: { CheckList }
})
export default class Password extends Vue {pagek = new Date().getTime();@Prop({type: Array as PropType<ruleItem[]>,required: true})checkList;@Prop({type: Array as PropType<ruleItem[]>,required: false})popover;private popoverOptions = {};checkValuesObj: any = {};passwordType: Boolean = true;created() {this.popoverOptions = { ...this.popover, ...popDefault };this.update(this.checkList);}update = (validList: string[] = [], clear: Boolean = false) => {// 每次update 前先清空 checkValuesObjObject.keys(this.checkValuesObj).forEach(v => {this.$set(this.checkValuesObj, v, "");});let tempObj = {};this.$nextTick(() => {this.pagek = new Date().getTime();tempObj =validList.length > 0 &&validList.reduce((res = {}, key = "1") => Object.assign(res, { [key]: "success" }),{});if (tempObj) {Object.keys(tempObj).forEach(v => {this.$set(this.checkValuesObj, v, tempObj[v]);});}if (clear) {Object.keys(this.checkValuesObj).forEach(v => {this.$set(this.checkValuesObj, v, "");});}});};triggerPassword() {this.passwordType = !this.passwordType;}
}
</script><style lang="scss" scoped>
.trigger-password {display: block;width: 24px;height: 100%;background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADmElEQVRoQ+2Y14vXUBCFv7X3Dgp2sIEVy4MP/vUKPth7x4q99658MIFLTDbJTRZ3IQNB/CV37pkzZ2bu3QlmuE3McPyMAfzvDI4ZGDPQk4FRQj0J7L18zEBvCns6mI4Z2AC8AL61iW26BbAV2Ax8Bk4Dv5uCGDKA2cCqeBYC84F5AeB7MPoFeB3PrxK4Arw/XwWeN4H3/RABCNq0rwBmtdk0mL0NPI7vs8D3DWB1pHtZAvo98BL4GIyr4z+RCTOyHFgZ767Hu2zwuQEIZGdIRR8/gIfAU0CpdLEUvLq/CHzt4qCrhNYB24A5wE/gfsgg1bPvNgJmyFowA4IyM49inRhT8PpynX7uJNJqjKVtAGpb1teGx1fAjQrGlceuKODy5hbltQrZ+NsbYAewJhY9AW4N1YVkZk8UqQzpWLmUTfD748d3IasP8f9FwNsa8M8SRxIkURJmUFeSjFVmoykD6n0vsCTYvgQUoFKHBnkkmH8A3A2w5U1T2dyskYpNwT3nAp8A96yti8kCkDUZNYimAiuAyfz5GvBbAJ/C7gE+VWbtGIQYbAz6FMM/VhfAAuBgtD9boyzYbepM9hcDl6NYy9+l4JWfzcBW67StMzOwO6RrOz5XlYm6AA4BSwEZtbWVp2Z502OAk/hkxRkmBW/BWgtHQ9snJgnAV/rcF/ND6Z4pfz/VAZTBW7BK0gAk5fhUBdBVQoej0C9E9xBXFXh/t1Xa1dpIyDqwqK2Ds10k5EZdiliwfl/0+TrwZvxASMIhaLeqMglUOvpU/xLTqYgLp+U2aj3IXNmKKerUTVulARV9XvC+2xSgTtX0eGtP5j3JupcNpPZu0DQHBCo4u4GDarJB5rcpeLtNwbCgPF54mNNSqaVk2J22R/EOMsgK51VHCQdRykwKvq42/d5TqOBSk20nsOcnzax5VBn8QpMy5FneIMoF61HDHm6xqmWz7EXG85OnVg9uhdkm14esigOi94Sqo0olKW0kVF4oKAOxCCfTfF0W/F3G9aGsDFbzpibrre7ChfOcAFJgqWwMxsGnPPxXILY/97AZ+HimMjPlS5BkmKHO1ieAtFU6XQXV5UrpGu8HMp9tuQFU9fm+l/qsIHICqBtSWQD6LuoagH998EqppUOqL47s9V0DsBC9I3iOb/V3m2xkLRd2DUC3FmrjgGm5f+/PcgLovemQDsYAhmQzx9eYgRzWhlwzZmBINnN8jRnIYW3INX8BE5PmMWUaunsAAAAASUVORK5CYII=")no-repeat center;background-size: 100%;cursor: pointer;&.show {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAC80lEQVRoQ+2XV4sVQRCFvzXnDIoYEExgVnzwwV/vgw8GjGBEzArmnJVvqYFhdubO9E4vy0oXXO6yt7u6zqlT1dVTLHCbWuDxUwDMdwZLBkoGRjJQJDSSwNHbSwZGUzjSQcnASAJHb8+ZgcXApvisBJYDyyLCH8B34CvwBngL/BodPWSZhQx6B7ABWDQwqL8B4nF8D9w2c9mYDGwGdgPram4/AK+AT8G4rGtmwoysBdy3vrbnI/Aw9iUDmQ0AAzkQUvHAn4BMvgCUyhBbCmyPzPm39hq4E8CH+JhekwpgG7AXWBIafgQ8BX7XTvS3ncG0taCpfQMUaF371o1AzGTl8z7wfCiCoQDUtqxvrbF1u4XxjcDBkEtbDErqVovuzer+AO0+AdwF/vQBGQJAZg5Hkcq0jpVL0wz+WPzzfbCtvjW1b1Yq7V/tKF4JkigJs1Pd7OtWfQBk5giwJti+FgXaDF6Qp4N5ZfUAsNPUzbP2ALtC5xc6grMpeKa18Rm4DnzrysQkAKuCUUF8AQy+y5GBqWOZv9ISfHW+5x2PTNh5BNpm1o4gjMHGoE9jmGFdAFYAJ6P92RplwW7TZbK/GrgxoB1uCUnaai9O8GkGDoV0BXG5jcAuAKdCtzIq8/Uu03bmWcCOcn5AGzSjZ8LnuZ4i1efRyJj1dKm5/r8FoIRORFHOp4SsA4s6WUJmaj6LWAKVjjF4d9h2k4q4klqzjVrMVW+vyzFnG/XOkHnnJwvdM6uZanAXagZnN/CimuuLzFFlXzSELBdZBWSuRwnZ9gZ2UtVeAo4qWUaJejaaw5yX0bOOYc5+r5a1lGHuXseo0tpx+0aJtk05xmkZlwzno2qc9qUm6516T7mJe+6X6Z8nPWgs9OoZ6drqeWmBmpnmI8hMOm4n22wy0DxkNk9Ktf0OeBJv5OTAqw05AFS+Uh71yqVvPBkEKieAQQfmXlQA5GY01V/JQCpjudeXDORmNNVfyUAqY7nXlwzkZjTVX8lAKmO51/8DYoDEMYv3QPQAAAAASUVORK5CYII=");}
}
</style>

CheckList 组件内容如下

<template><div class="check-list" :key="pagek"><div class="check-list__title">{{ title }}</div><div v-for="{ key, label } in options" :key="key"><div class="check-list-item"><span class="check-list-item__prefix"><iv-if="isEqual(key, 'success')"class="iconfont el-icon-success"></i><iv-else-if="isEqual(key, 'error')"class="iconfont el-icon-error"></i><iv-else-if="isEqual(key, 'warning')"class="iconfont el-icon-warning"></i><i v-else-if="isEqual(key, 'info')" class="el-icon-info"></i><i v-else class="iconfont el-icon-pending"></i></span><div class="check-list-label">{{ label }}</div></div></div></div>
</template><script lang="ts">
import { Component, Prop, Vue, Watch, Computed } from "vue-property-decorator";interface option {key: string | number | symbol;label: string;
}@Component({})
export default class CheckList extends Vue {status = ["pending", "success", "error", "warning", "info"];@Prop({default: new Date().getTime()})pagek;@Prop({type: Object,default: () => ({})})values;@Prop({type: Array as PropType<option[]>,default: () => []})options;@Prop({type: String,default: ""})title;get defaultStatus() {return this.options.reduce((res, { key }) => Object.assign(res, { [key]: status[0] }),{});}get statusMap() {return Object.assign({}, this.defaultStatus, this.values);}isEqual = (key: string | number | symbol,statusCode: string | number): boolean => {return this.statusMap[key] == statusCode;};
}
</script><style lang="scss" scoped>
// 胶囊状态颜色
$--color--capsule--success: #40b828;
$--color--capsule--danger: #f0553a;
$--color--capsule--cancel: #878e99;
$--color--capsule--warning: #fc971c;
$--color--capsule--processing: #1a9bf6;
$--color--capsule--info: #878e99;
.el-icon-success {color: $--color--capsule--success;
}
.el-icon-error {color: $--color--capsule--danger;
}
.el-icon-warning {color: $--color--capsule--warning;
}
.el-icon-info {color: $--color--capsule--info;
}
.el-icon-pending {&::before {content: "";display: inline-flex;width: 12px;height: 12px;border: 2px solid rgba(#000, 0.15);border-radius: 50%;// vertical-align: baseline;// margin-bottom: -2px;}
}.check-list {font-size: 13px;
}
.check-list__title {line-height: 20px;color: $--color-text-lighter;margin-bottom: 12px;
}
.check-list-item {line-height: 20px;margin-bottom: 8px;
}
.check-list-item__prefix {float: left;font-size: 16px;
}
.check-list-label {margin-left: 16px + 12px;
}
</style>

由于我们项目使用了 ts ,因此会有一些必要的类型校验
index.type.ts 内容如下

export interface rule {key: string;label: string;
}export interface ruleItem extends rule {regExp?: RegExp;validator?: (value: string) => boolean;
}

utils.ts 中为校验规则,以及校验结果

import { ruleItem } from "./index.type";
import i18nInstance from "@root/i18n";export const usePassword = (options?: Array<ruleItem | string>) => {const defaultRules: ruleItem[] = [{key: "length",label: i18nInstance.t("Basic.At_least_8_characters"),regExp: /^.{8,}$/},{key: "lowercase",label: i18nInstance.t("Basic.Use_lowercase_letters"),regExp: /[a-z]+/},{key: "capital",label: i18nInstance.t("Basic.Use_capital_letters"),regExp: /[A-Z]+/},{key: "number",label: i18nInstance.t("Basic.Use_numbers"),regExp: /\d{1,}/},{key: "special",label: i18nInstance.t("Basic.Use_special_characters"),regExp: /[!@#$%^&*? ]{1,}/}];const ruleItems: ruleItem[] = options? options.reduce((res, item) => {if (typeof item === "string") {const rule = defaultRules.find(i => item === i.key);if (rule) {res.push(rule);} else {throw new Error("invalid ruleKey");}} else {res.push(item);}return res;}, [] as ruleItem[]): [...defaultRules];// 返回默认的匹配规则map 和 校验结果mapListreturn {checkList: ruleItems.map(({ key, label }) => ({ key, label })),validate: (value: string): { validList: string[]; valid: boolean } => {// 过滤出符合正则的rule[], map返回key[]const validList = ruleItems.filter(({ regExp, validator }) => {if (validator) {return validator(value);} else if (regExp) {return regExp.test(value);} else {return false;}}).map(({ key }) => {return key;});return {validList,valid: validList.length === ruleItems.length};}};
};

为了方便使用容易将逻辑与组件放入index.ts

import Password from "./src/index.vue";
import { usePassword } from "./src/utils";export { usePassword };export default Password;

三 使用组件

import Password, { usePassword } from "@/components/page/Password/index"; //引入组件passwordE = null; // password 组件元素相关校验逻辑...
created() { //组件生命周期内使用组件this.passwordE = usePassword();this.checkList = this.passwordE.checkList;}
...// 密码规则自定义校验器
get rules(){let _ = this;
return {password: {validator: (rule: any,value: string,callback: (v?: Error) => void) => {const { validList = [], valid } = _.passwordE.validate(value);(_.$refs.passwordRef as any).update(validList);// 几条规则是否都以校验完成,否则会有无效密码提示if (!valid) {callback(new Error(_.$t("Basic.invalid_password") as string));} else {callback();}},trigger: ["change", "blur"]},}
}

Vue2.x+Element UI 密码规则组件封装相关推荐

  1. DataGear 制作基于Vue2、Element UI前端框架的数据可视化看板

    DataGear 数据可视化看板内置了一些基本.简单的页面交互组件,当它们无法满足实际看板需求时,可以引入更流行和强大的前端框架. 本文以Vue2.Element UI前端框架为例,介绍如何制作具有更 ...

  2. element ui 弹出组件的遮罩层在弹出层的上面的解决方法

    element ui 弹出组件的遮罩层在弹出层的上面的解决方法 参考文章: (1)element ui 弹出组件的遮罩层在弹出层的上面的解决方法 (2)https://www.cnblogs.com/ ...

  3. (vue+【饿了么UI】tag组件封装)

    (vue+[饿了么UI]tag组件封装) 根据项目所衍生的一种tag组件,废话不多说直接上代码 <template> <div><!-- 素材标签 --><d ...

  4. element UI上传图片Upload组件使用 图片转base64和fale文件处理 formdata数据格式的应用

    element UI上传图片Upload组件使用 & 图片转base64和fale文件处理 & formdata数据格式的应用 1.element UI上传图片Upload组件使用 效 ...

  5. vue问题三:element ui的upload组件上传图片成功和移除事件

    element ui的upload组件上传图片成功和移除事件: 登录后获取到后台传的token存到中: sessionStorage.setItem("token",data.ob ...

  6. Element UI(桌面组件库)之 三大灵魂拷问

    1. 什么是Element UI 概述 Element,一套为开发者.设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 Element UI是基于Vue 2.0的 Element UI 提供 ...

  7. element ui 多个子组件_ElementUI 技术揭秘(2) 组件库的整体设计

    需求分析 当我们去实现一个组件库的时候,并不会一上来就撸码,而是把它当做产品一样,思考一下我们的组件库的需求.那么对于 element-ui,除了基于 Vue.js 技术栈开发组件,它还有哪些方面的需 ...

  8. 关于Element UI中select组件中遇到的问题

    问题一:在使用select组件设置多选功能后,窗口抖动问题? 详细描述:在我使用select做多选的功能时出现了窗口抖动的问题,测试的时候发现,在有些人的电脑上抖动,有些人的电脑上不抖,找了很多文档, ...

  9. vue2引入Element UI的详细步骤

    目录 一.Element UI介绍 Element UI的特点: vue3引入Element plus的文章: 二.操作步骤 三.快速上手测试(可做可不做) 一.Element UI介绍 Elemen ...

  10. vue2.0 + element ui 实现表格穿梭框

    element ui 官网里介绍了穿梭框(Transfer),但在实际使用过程中,会出现一些问题: 1.穿梭框里能放置的内容太少,不能满足复杂的业务需求. 2.当选项过多时,穿梭框很难实现分页,左右两 ...

最新文章

  1. vue样式 引入图片_详解Vue.js中引入图片路径的几种方式
  2. OpenAI智能体上演捉迷藏攻防大战,自创套路与反套路
  3. mysql 快速升级_MySQL 4到5的快速升级
  4. c++primer plus 第11章 编程题第7题
  5. 【转】应用架构一团糟?如何将单体应用改造为微服务
  6. 如何解决Android studio已分享到github的项目但是git->commit directory提交不上去
  7. 计算机主板另一个名称,主板名称太复杂 看这几点就秒懂了
  8. Delphi编程 -- 如何实现一个支持Visual Basic的For Each调用的COM对象
  9. LeetCode OJ:Maximal Rectangle(最大矩形)
  10. 查询工资最低的3名员工的职工工号、姓名和收入_2018年31省最低工资排名!武汉工资低于这个数就违法!...
  11. 计算机学数字电子基础知识,什么是数字电路?数字电路基础知识
  12. 超级详细的java Collection集合面试题
  13. mac os android 线刷,Mac系统下使用Fastboot线刷安卓设备
  14. 远程无人值守批量装机(图文详解)
  15. ansible一键部署zabbix并配置自动发现
  16. 电流检测应用开发的高隔离集成式霍尔电流传感芯片--CH701W
  17. 在5G智慧园区的“保龄球道”上,目标全垒打的征途
  18. 华为cmr一al09升级鸿蒙,华为平板 M5 10.8英寸 全网通(CMR-AL09)一键刷机教程,看教程秒懂刷机...
  19. java里remark是什么意思_remark_remark的意思和用法搭配
  20. 蓝桥杯真题:第几个幸运数字

热门文章

  1. 猫哥教你写爬虫 029--爬虫初探-requests
  2. flutter打包出错了,有大神帮忙看看吗?
  3. 我们为什么做不好软件项目?做项目时间都浪费在反复奸奸杀杀,杀杀奸奸上了
  4. Google Analytics SEO 实时 网站 访问量 统计
  5. vue里删除购物车商品(购物车功能六)
  6. ANSYS ICEM CFD二维结构网络生成实例——流动传热
  7. Island Transport
  8. Win10下执行mklink提示你没有足够权限执行此操作
  9. 不交智商税,如何判断一场知乎live的质量?
  10. USB之:MTKUSB软件框架及其MassStorage Class规范学习