《论 · 前端设计模式之一:单例模式》

203 阅读3分钟

前端有很多的设计模式,比较出名的有发布订阅者模式,观察者模式...等等还有很多,今天要讲的是设计模式之一的 《单例模式》。单例的模式的应用场景较多的,就是在组件封装这块,我们经常在组件封装的时候,发现封装后的组件在页面运用的时候会多次创建同样的实例,这种情况下,我们可以创建相同的实例,且使用的过程中都是用的同一个实例对象。

### 一:先创建一个构造函数,看看能不能创建相同的实例😁

function Fun(name){
    this.name = name;
}

let instance = null;

function fun(name){
     null  默认是false 取反就是成立 
     第二次执行该函数的时候,instance内部是上一次的实例,所以成立
    if(!instance) instance = new Fun(name);
     return instance
}

let a = fun('康康也爱玩游戏');
let b = fun('康康不爱玩游戏');

console.log(a,b);
console.log(a == b); //你会发现这里打印的true,说明是用的上一次示例,并没有新建实例
    
### 二:这个时候时候我们可以对代码进行一次升级🙄
            细节:
            1.加上了自执行函数/闭包
            2.可以进行在同一文件,多次暴露不同组件
            3.便于访问,后期可以通过一开始的person变量对返回的函数进行一个访问

        const person = (()=>{
            function Fun(name,age,sex){
                this.name = name;
                this.age = age;
                this.sex = sex
            }
            Fun.prototype.say = function(){
                console.log('hello world');
            }
            let instance = null;
            return (name,age,sex)=>{
                if(!instance) instance = new Fun(name,age,sex);
                return instance
            }
        })()

        const a = person('海绵宝宝',18,'男');
        const b = person('派大星',19,'男');
        console.log(a == b); //true 发现可以完成,也就是说,组件封装在构造函数内部,多次
        使用并不会创造不同的实例对象
        
### 最后一次升级,康康一下内部的组件,封装能不能成功哈😏
        细节:
        1.直接上class类构造函数,面向对象封装
        const KangComponent = (()=>{
            class Base_popUp{
                constructor(){
                    this.Element = document.createElement('div');
                    this.callback = function(){}
                }
        exhibition(HeaderTitle = '标题',SearchTitle = '请输入您的名字',SearchValue = ''){
            this.Element.style.width = window.innerWidth + 'px';
            this.Element.style.height = window.innerHeight + 'px';
            document.body.style.overflow = 'hidden';
            this.Element.className = 'kang_template';
            document.body.appendChild(this.Element)
            this.Element.innerHTML = `
                <div class="box">
                    <div class="header">
                        <h4>${HeaderTitle}</h4>
                        <div class="close">x</div>    
                    </div>
                    <div class="body">
                        <div class="content">
                            <div>${SearchTitle}</div>
                            <div>
                                <input type="text" placeholder=${SearchValue} >    
                            </div>
                        </div>
                    </div>
                    <div class="footer">
                        <button class="cancel">取消</button>
                        <button class="affirm">确认</button>
                    </div>
                </div>
            `
            this.Element.style.display = 'block'
            this.monitor();
            this.binding();
        }
        monitor(){          
            window.addEventListener('resize',()=>{
                this.Element.style.width = window.innerWidth + 'px';
                this.Element.style.height = window.innerHeight + 'px';
            })
        }
        binding(){
            this.Element.addEventListener('click',(e)=>{
                e = e || window.event;
                if(e.target.className === "close"){
                    this.Element.style.display = 'none'
                }else if(e.target.className === "cancel"){
                    this.Element.style.display = 'none';
                }else if(e.target.className === "affirm"){
                    this.Element.style.display = 'none'
                    this.callback();
                }
            })
        }
    }
        let instance = null;
        return ({ headerTitle , bodyTitle , bodyContent}, callback)=>{
        if(!instance) instance = new Base_popUp();
        instance.exhibition( headerTitle , bodyTitle , bodyContent );
        instance.callback = callback;
        return instance
    }
})()  

    然后来一部分基础样式哈!!!
  *{
     margin:0;
     padding:0;
 }
.kang_template{
    position: absolute;
    top: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.3);/*最后一项即为透明度*/
    z-index: 1;
    display: none;
}
.kang_template .box{
    width: 430px;
    height: 220px;
    box-sizing: border-box;
    padding:10px;
    border-radius:8px;
    box-shadow: 0px 0px 10px 5px #999;
    position: absolute;
    margin: auto;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background:#fff;
    z-index: 999;
}
.kang_template .header{
    height: 30px;
    box-sizing: border-box;
    padding:5px;
    display: flex;
    justify-content: space-between;
    border-bottom:1px solid black;
}
.kang_template .header div{
    width: 19px;
    text-align: center;
    line-height:19px;
    cursor: pointer;
}
.kang_template .header div:hover{
    color: skyblue;
}
.kang_template .body{
    box-sizing: border-box;
    padding:5px;

}
.kang_template .body .content{
    height: 105px;
}
.kang_template .body .content div{
    margin-top:20px
}

.kang_template .body .content>div:nth-child(2){
    border-radius: 4px;
    border: 1px solid #dcdfe6;
}
.kang_template .body .content input{
    width: 377px;
    height: 40px;
    outline-style: none;
    border: none;
    margin-left: 20px;
    font-size: 16px;
}
.kang_template .footer{
    box-sizing: border-box;
    padding:5px;
    height: 35px;
    display: flex;
    justify-content: space-between;
}
.kang_template .footer button{
    width: 100px;
    height: 100%;
    border-color: #dcdfe6;
    background-color: #fff;
    color: #606266;
    border-radius: 4px;
    cursor: pointer;
}
.kang_template .footer button:nth-child(2){
    background-color:#409Eff;
    color: #fff;
    border-color: #409eff;
}
.kang_template .footer button:nth-child(1):hover{
    background-color: #ecf5ff;
    color: #409eff;
    border-color: #c6e2ff;
}
.kang_template .footer button:nth-child(2):hover{
    background-color: #8fc4f8;
    border-color: #8fc4f8
}

然后,这个是向外暴露的api
    KangComponent({ 
         headerTitle : '',
         bodyTitle : '卧槽',
         bodyContent : 'helloWorld'
    },()=>{
         console.log('Hello World');
     })
可以传一个3个参数和一个回调,点击确认后会触发哈

核心其实就是在instance这块,因为第一次已经实例化过了,第二次则不会通过,会继续沿用上一次的实例

# 第一次写文章,有不对的地方麻烦大家批评指正下!!!😂😂😂ヾ(≧▽≦*)o