单例模式
优势和特点:单例模式主要解决的问题就是节约资源,保持访问一致性。保证一个类只有一个实例,并提供一个访问它的全局访问点。
简单实现(闭包)
const Person = (() => {
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
intro() {
console.log(`my name is ${this.name}`);
}
}
let instance = null
// 有实例就返回,无则创建
return function singleTon(...args) {
if (!instance) instance = new Person(...args)
return instance
}
})()
const p1 = new Person("zs", 19)
const p2 = new Person("ls", 20)
console.log(p1 === p2); //true
p1.intro() //my name is zs
p2.intro() //my name is zs
应用举例
- element-ui中Loading,当以服务的方式调用的全屏 Loading 是单例的:若在前一个全屏 Loading 关闭前再次调用全屏 Loading,并不会创建一个新的 Loading 实例,而是返回现有全屏 Loading 的实例:
let loadingInstance1 = Loading.service({ fullscreen: true });
let loadingInstance2 = Loading.service({ fullscreen: true });
console.log(loadingInstance1 === loadingInstance2); // true
- vuex 使用单一状态树,实现了一个全局的 Store 用于存储应用的所有状态,
import Vue from 'vue'
import Vuex from 'vuex'
// Vuex在内部实现了一个 install 方法,这个方法会在插件安装时被调用, 可以保证一个 Vue 实例(即一个 Vue 应用)只会被 install 一次 Vuex 插件,所以每个 Vue 实例只会拥有一个全局的 Store。
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
new Vue({
el: '#app',
store: store,
})
工厂模式
优势和特点:外部不许关心内部构造器是怎么生成的,只需调用一个工厂方法生成一个实例即可。传入不同的参数,获取对应的功能。
简单实现(switch case)
class User {
constructor(name = '', viewPage = []) {
this.name = name;
this.viewPage = viewPage;
}
}
class UserFactory extends User {
constructor(name, viewPage) {
super(name, viewPage)
}
create(role) {
switch (role) {
case 'superAdmin':
return new UserFactory( '超级管理员', ['首页', '通讯录', '发现页', '应用数据', '权限管理'] );
break;
case 'admin':
return new UserFactory( '普通用户', ['首页', '通讯录', '发现页'] );
break;
case 'user':
return new UserFactory( '普通用户', ['首页', '通讯录', '发现页'] );
break;
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
}
let userFactory = new UserFactory();
let superAdmin = userFactory.create('superAdmin');
let admin = userFactory.create('admin');
let user = userFactory.create('user');
应用举例
- vue-router
export default class VueRouter {
constructor({mode, base} = {}) {
switch (mode) {
case 'history':
this.history = new HTML5History(this, base)
break
case 'hash':
this.history = new HashHistory(this, base, this.fallback)
break
default:
}
}
}
策略模式
优势和特点:策略模式根据传入的参数,来调整采用对应的算法。
应用举例
- element-ui中的表单项校验
// 1.src/utils/validates.js
// 姓名校验 由2-10位汉字组成
export function validateUsername(str) {
const reg = /^[\u4e00-\u9fa5]{2,10}$/
return reg.test(str)
}
// 手机号校验 由以1开头的11位数字组成
export function validateMobile(str) {
const reg = /^1\d{10}$/
return reg.test(str)
}
// 邮箱校验
export function validateEmail(str) {
const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
return reg.test(str)
}
// 2.src/utils/index.js
import * as Validates from './validates.js'
// 生成表格自定义校验函数
export const formValidateGene = (key, msg) => (rule, value, cb) => {
if (Validates[key](value)) {
cb()
} else {
cb(new Error(msg))
}
}
// 3.组件中使用
<template>
<el-form ref="ruleForm"
:rules="rules"
:model="ruleForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="ruleForm.mobile"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="ruleForm.email"></el-input>
</el-form-item>
</el-form>
</template>
<script type='text/javascript'>
import * as Utils from '../utils'
export default {
name: 'ElTableDemo',
data() {
return {
ruleForm: { pass: '', checkPass: '', age: '' },
rules: {
username: [{
validator: Utils.formValidateGene('validateUsername', '姓名由2-10位汉字组成'),
trigger: 'blur'
}],
mobile: [{
validator: Utils.formValidateGene('validateMobile', '手机号由以1开头的11位数字组成'),
trigger: 'blur'
}],
email: [{
validator: Utils.formValidateGene('validateEmail', '不是正确的邮箱格式'),
trigger: 'blur'
}]
}
}
}
}
</script>
发布订阅模式
优势和特点:一个地方触发,能通知多个订阅者
简单实现, juejin.cn/post/713768…
应用举例
- EventBus
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
// 监听方
import { EventBus } from './event-bus.js'
EventBus.$on('addition', param => { })
// 发送方
import {EventBus} from './event-bus.js' // 引入事件中心
EventBus.$emit('addition', { num:123 })
拦截器模式
优势和特点:入口或出口地方进行拦截,集中式处理
应用举例
- axios请求响应拦截器
- Vue Router 导航守卫
装饰器模式
优势和特点:辅助功能和业务功能分离。
应用举例
- 防抖节流装饰器
// @/decorator/index.js
import { throttle, debounce } from 'lodash'
export const Throttle = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = throttle(descriptor.value, wait, options)
}
}
export const Debounce = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = debounce(descriptor.value, wait, options)
}
}
//在组件中使用
import { Debounce } from '@/decorator'
export default {
methods:{
// 这样resize方法就自带有防抖功能了
@Debounce(100)
resize(){}
}
}
- form表单的校验
// @/utils/decorator
export function Validate(refName) {
return function (target, name, descriptor) {
const fn = target[name]; // 被装饰的方法
descriptor.value = function (...args) {
// 将触发校验的代码封装在此
this.$refs[refName].validate((valid) => {
if (valid) {
fn.call(this, ...args); // 在这里调用“被装饰的方法”
} else {
console.log('error submit!!');
return false;
}
});
};
};
}
//在组件中使用
import { Validate } from '@/utils/decorator'
export default {
methods:{
// 这样就会自动校验表单,校验成功才会执行submitForm中的代码了
@Validate('formName')
async submitForm() {
await this.saveRequest();
}
}
}
- 删除业务的确认框(点击删除按钮的时候,一般都需要弹出一个提示框让用户确认是否删除)