前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >39·灵魂前端工程师养成-MVC

39·灵魂前端工程师养成-MVC

作者头像
DriverZeng
发布2022-11-08 17:05:13
6780
发布2022-11-08 17:05:13
举报

-曾老湿, 江湖人称曾老大。 -笔者QQ:133411023、253097001 -笔者交流群:198571640 -笔者微信:z133411023


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


MVC设计模式


什么是MVC

MVC是个框,什么都能往里装

MVC主要目的就是为了减少重复性的工作,重复性的代码。

代码级别的重复 你把相同的三行代码写了两遍 那么你就应该重构它

页面级别 你把类似的页面做了10遍 那么你就应该相处一个万金油的写法

MVC就是一个万金油 所有页面都可以使用MVC来优化代码结构


如果我们不学MVC会怎么样

意大利面条式代码 老手程序要为了鄙视烂代码,将其称为面条式代码

你将变成外包程序员 不停重复自己,不懂得抽象 只会调用API,不能提升自己 只会写业务,不会封装,更不会造轮子,更不会加薪


那我学还不行嘛

MVC介绍 每个模块都可以写成三个对象,分别是:M、V、C M: Model(数据模型)负责操作所有数据 V: View (视图)负责所有UI界面 C: Controller (控制器)负责其他

就这? 嗯呢,就这 MVC没有严格的定义 M、V、V分别要做什么也是很随意的,大概对就行

在程序猿的世界里,很多定义,都是模糊的定义,所以很多程序猿对这些定义的认知都多少有些偏差,不相同的地方,唯一一点认同的一样的地方,那就是M、V、C这三个单词分别是啥,一点偏差都没有,没有任何分歧。

先写一个意大利面条式的烂代码


初始化项目

抄淘宝的viewport

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
   <script src="main.js"></script> 
</body>
</html>

实现需求:把一个页面分4块,每一个块里面有一个功能 1.左上角的块,实现100数字的加减乘除 2.右上角的块,实现tab标签的切换,并且高亮 3.左下角的块,实现一个形状的动画 4.右下角的块,实现一个颜色的渐变


创建4个块

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div id="app1"></div>
    <div id="app2"></div>
    <div id="app3"></div>
    <div id="app4"></div>
   <script src="main.js"></script> 
</body>
</html>

第一个块制作按钮

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div id="app1">
        <div class="output">
            <span>100</span>
        </div>
        <div class="actions">
            <button>+1</button>
            <button>-1</button>
            <button>*2</button>
            <button>÷2</button>
        </div>
    </div>
    <div id="app2"></div>
    <div id="app3"></div>
    <div id="app4"></div>
   <script src="main.js"></script> 
</body>
</html>


JS引入CSS

代码语言:javascript
复制
import './app1.css'

CSS添加选择器

先把选择器写好,再加功能,然后给app1加一个边框

代码语言:javascript
复制
#app1{
    border: 1px solid red;
}
#app1 .output{}
#app1 .actions{}


写一个CSS的reset用JS引入

代码语言:javascript
复制
*{margin: 0;padding: 0;}
代码语言:javascript
复制
import './reset.css'
import './app1.css'


让第一个app占屏幕的四分之一

代码语言:javascript
复制
#app1{
    border: 1px solid red;
    width: 50vw;
    height: 50vh;
}
#app1 .output{}
#app1 .actions{}


新的方式引入jQuery

首先使用npm或者yarn安装jQuery

代码语言:javascript
复制
#方法一
MacBook-pro:mvc-demo-1 driverzeng$ yarn init -y
MacBook-pro:mvc-demo-1 driverzeng$ yarn global add  jquery

代码语言:javascript
复制
#方法二
MacBook-pro:mvc-demo-1 driverzeng$ npm i jquery

会发现多了几个东西

然后我们调用jQuery

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

实现第一个模块-加减乘除按钮


先给4个按钮加上id

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div id="app1">
        <div class="output">
            <span id="number">100</span>
        </div>
        <div class="actions">
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">*2</button>
            <button id="divide2">÷2</button>
        </div>
    </div>
    <div id="app2"></div>
    <div id="app3"></div>
    <div id="app4"></div>
   <script src="main.js"></script> 
</body>
</html>

使用js获取4个button

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')

添加事件-实现加法

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    $number.text(n)
})


添加事件-实现减法

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    $number.text(n)
})


添加事件-实现乘法

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    $number.text(n)
})

$button3.on("click",()=>{
    let n = parseInt($number.text())
    n *= 2
    $number.text(n)
})


添加事件-实现除法

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    $number.text(n)
})

$button3.on("click",()=>{
    let n = parseInt($number.text())
    n *= 2
    $number.text(n)
})

$button4.on("click",()=>{
    let n = parseInt($number.text())
    n /= 2
    $number.text(n)
})


当用户刷新的时候,还是那个数字不变回100

代码语言:javascript
复制
import './reset.css'
import './app1.css'
import $ from 'jQuery'

const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')
const n = localStorage.getItem('n')
$number.text(n || 100)

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button3.on("click",()=>{
    let n = parseInt($number.text())
    n *= 2
    localStorage.setItem('n',n)
    $number.text(n)
})

$button4.on("click",()=>{
    let n = parseInt($number.text())
    n /= 2
    localStorage.setItem('n',n)
    $number.text(n)
})

实现第二个模块-点击标签实现切换


先添加两个列表

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div id="app1">
        <div class="output">
            <span id="number">100</span>
        </div>
        <div class="actions">
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">*2</button>
            <button id="divide2">÷2</button>
        </div>
    </div>
    <div id="app2">
        <ol class="tab-bar">
            <li>1</li>
            <li>2</li>
        </ol>
        <ol class="tab-content">
            <li>内容1</li>
            <li>内容2</li>
        </ol>
    </div>
    <div id="app3"></div>
    <div id="app4"></div>
   <script src="main.js"></script> 
</body>
</html>

接下来做一下CSS的reset

代码语言:javascript
复制
*{box-sizing: border-box;margin: 0;padding: 0;}
*::before,*::after{box-sizing: border-box;}
ol,ul{list-style: none;}

修改css样式

app2.css

代码语言:javascript
复制
#app2{
    border: 1px solid blue;
    width: 50vw;
    height: 50vh;
}
#app2 .tab-bar{}
#app2 .tab-content{}

在js中引入

代码语言:javascript
复制
import './app2.css'


做flex布局

因为我们想要把这个功能放在右上角,所以我们需要创建一个div包裹住这四个app

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page">
        <div id="app1">
            <div class="output">
                <span id="number">100</span>
            </div>
            <div class="actions">
                <button id="add1">+1</button>
                <button id="minus1">-1</button>
                <button id="mul2">*2</button>
                <button id="divide2">÷2</button>
            </div>
        </div>
        <div id="app2">
            <ol class="tab-bar">
                <li>1</li>
                <li>2</li>
            </ol>
            <ol class="tab-content">
                <li>内容1</li>
                <li>内容2</li>
            </ol>
        </div>
        <div id="app3"></div>
        <div id="app4"></div>
    </div>
   <script src="main.js"></script> 
</body>
</html>

我们不能把page的CSS写在app1里也不能写在app2里,所以我们需要创建一个新的。所以我们再创建一个全局的CSS

代码语言:javascript
复制
body  > .page{
    display: flex;
}


修改全局

因为我们每个框,都占四分之一,所以我们把重复代码写到全局css中,那我们先把每个app的div换成section

index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page">
        <section id="app1">
            <div class="output">
                <span id="number">100</span>
            </div>
            <div class="actions">
                <button id="add1">+1</button>
                <button id="minus1">-1</button>
                <button id="mul2">*2</button>
                <button id="divide2">÷2</button>
            </div>
        </section>
        <section id="app2">
            <ol class="tab-bar">
                <li>1</li>
                <li>2</li>
            </ol>
            <ol class="tab-content">
                <li>内容1</li>
                <li>内容2</li>
            </ol>
        </section>
        <section id="app3"></div>
        <section id="app4"></div>
    </div>
   <script src="main.js"></script> 
</body>
</html>

然后再写全局

global.css

代码语言:javascript
复制
body{
    overflow: hidden;
}
body  > .page{
    display: flex;
    flex-wrap: wrap;
}
body  > .page > section{
    width: 50vw;
    height: 50vh;
    border: 1px solid gray;
}

app1.css

代码语言:javascript
复制
#app1{
    border: 1px solid red;
}
#app1 .output{}
#app1 .actions{}

app2.css

代码语言:javascript
复制
#app2{
    border: 1px solid blue;
}
#app2 .tab-bar{}
#app2 .tab-content{}

模块化

对应的app创建对应的css和js,所以我们把代码重新移动一下

main.js

代码语言:javascript
复制
import './reset.css'
import './global.css'
import './app1.css'
import './app2.css'
import './app3.css'
import './app4.css'
import './app1.js'
import './app2.js'
import './app3.js'
import './app4.js'

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')
const n = localStorage.getItem('n')
$number.text(n || 100)

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button3.on("click",()=>{
    let n = parseInt($number.text())
    n *= 2
    localStorage.setItem('n',n)
    $number.text(n)
})

$button4.on("click",()=>{
    let n = parseInt($number.text())
    n /= 2
    localStorage.setItem('n',n)
    $number.text(n)
})


实现功能

app2.js

代码语言:javascript
复制
import $ from 'jquery'
const $tabBar =  $('#app2 .tab-bar')
const $tabConten = $('#app2 .tab-content')

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    const index = $li.index()
    $tabConten.children()
    .eq(index).css({display:'block'})
    .siblings().css({display:'none'})
})

点1,就是内容1 点2,就是内容2

但是。。。这样的代码不要用,不要使用js直接操作css,所以我们需要换个思想

只要一点击,就add一个active的class,那么另外一个就remove这个active的class

代码语言:javascript
复制
import $ from 'jquery'
const $tabBar =  $('#app2 .tab-bar')
const $tabConten = $('#app2 .tab-content')

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    const index = $li.index()
    $tabConten.children()
    .eq(index).addClass('active')
    .siblings().removeClass('active')
})
代码语言:javascript
复制
#app2{
    border: 1px solid blue;
}
#app2 .tab-bar{
    display: flex;
}
#app2 .tab-bar  > li{
    border: 3px solid black;
    width: 50%;
}

#app2 .tab-content{}

#app2 .tab-content > li{
    display: none;
}
#app2 .tab-content > li.active{
    display: block;
}


内容切换完成了,再给标签加个颜色

app2.js

代码语言:javascript
复制
import $ from 'jquery'
const $tabBar =  $('#app2 .tab-bar')
const $tabConten = $('#app2 .tab-content')

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    $li
        .addClass("selected")
        .siblings()
        .removeClass('selected')
    const index = $li.index()
    $tabConten
        .children()
        .eq(index)
        .addClass('active')
        .siblings()
        .removeClass('active')
})

app2.css

代码语言:javascript
复制
#app2{
    border: 1px solid blue;
}
#app2 .tab-bar{
    display: flex;
}
#app2 .tab-bar  > li{
    border: 1px solid gray;
    width: 50%;
}

#app2 .tab-bar  > li.selected{
    background: palevioletred;
    color: white;
}

#app2 .tab-content{}

#app2 .tab-content > li{
    display: none;
}
#app2 .tab-content > li.active{
    display: block;
}


添加默认点击效果

app2.js

代码语言:javascript
复制
import $ from 'jquery'
const $tabBar =  $('#app2 .tab-bar')
const $tabContent = $('#app2 .tab-content')

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    $li
        .addClass("selected")
        .siblings()
        .removeClass('selected')
    const index = $li.index()
    $tabContent
        .children()
        .eq(index)
        .addClass('active')
        .siblings()
        .removeClass('active')
})

$tabBar.children().eq(0).trigger('click')

实现第三个模块-方块变成圆动画


创建js和css并引入

main.js

代码语言:javascript
复制
import './reset.css'
import './global.css'
import './app1.css'
import './app2.css'
import './app3.css'
import './app4.css'
import './app1.js'
import './app2.js'
import './app3.js'

添加方块的div

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page">
        <section id="app1">
            <div class="output">
                <span id="number">100</span>
            </div>
            <div class="actions">
                <button id="add1">+1</button>
                <button id="minus1">-1</button>
                <button id="mul2">*2</button>
                <button id="divide2">÷2</button>
            </div>
        </section>
        <section id="app2">
            <ol class="tab-bar">
                <li>1</li>
                <li>2</li>
            </ol>
            <ol class="tab-content">
                <li>内容1</li>
                <li>内容2</li>
            </ol>
        </section>
        <section id="app3">
            <div class="square"></div>
        </section>
        <section id="app4"></section>
    </div>
   <script src="main.js"></script> 
</body>
</html>

监听点击事件

代码语言:javascript
复制
import $ from 'jquery'
const $square = $('#app3 .square')

$square.on('click',()=>{
    $square.toggleClass('active')
})

添加动画

代码语言:javascript
复制
#app3{

}

#app3 .square{
    border: 1px solid gray;
    width: 10vw;
    height: 10vw;
    margin-top: 10vw;
    margin-left: 10vw;
    transition: transform 1s;
}

#app3 .square.active{
    transform: translateX(15vw);
}


加边框到全局css

代码语言:javascript
复制
body{
    overflow: hidden;
}
body  > .page{
    display: flex;
    flex-wrap: wrap;
}
body  > .page > section{
    width: 50vw;
    height: 50vh;
    border: 1px solid gray;
}

实现第四个模块-点击圆会渐变


添加app4的css和js

创建并引入

代码语言:javascript
复制
import './reset.css'
import './global.css'
import './app1.css'
import './app2.css'
import './app3.css'
import './app4.css'
import './app1.js'
import './app2.js'
import './app3.js'
import './app4.js'


写样式

代码语言:javascript
复制
#app4{

}
#app4 .circle{
    border: 1px solid green;
    width: 20vw;
    height: 20vw;
    border-radius: 50%;
}


加动画

代码语言:javascript
复制
#app4{

}
@keyframes change{
    0%{
        background: pink;
    }
    30%{
        background: plum;
    }
    60%{
        background: powderblue;
    }
    100%{
        background:blue;
    }
}
#app4 .circle{
    border: 1px solid green;
    width: 20vw;
    height: 20vw;
    border-radius: 50%;
    animation: change 2s infinite alternate linear;
}


修改鼠标移动才变

同样,添加一个active的类,然后用鼠标激活

代码语言:javascript
复制
#app4{

}
@keyframes change{
    0%{
        background: pink;
    }
    30%{
        background: plum;
    }
    60%{
        background: powderblue;
    }
    100%{
        background:blue;
    }
}
#app4 .circle{
    border: 1px solid green;
    width: 20vw;
    height: 20vw;
    border-radius: 50%;
}
#app4 .circle.active{
    animation: change 2s infinite alternate linear;
}

监听鼠标事件

代码语言:javascript
复制
import $ from 'jquery'
const $circle = $('#app4 .circle')
$circle.on('mouseenter',()=>{
    $circle.addClass('active')
}).on('mouseleave',()=>{
    $circle.removeClass('active')
})

app2数据保存

我们要保证,用户将标签切换到2的时候,即便是刷新页面还在2


修改app2的JS

代码语言:javascript
复制
import $ from 'jquery'
const $tabBar =  $('#app2 .tab-bar')
const $tabContent = $('#app2 .tab-content')
const localKey = 'app2.index'
const index =  localStorage.getItem(localKey) || 0

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    $li
        .addClass("selected")
        .siblings()
        .removeClass('selected')
    const index = $li.index()
    localStorage.setItem(localKey,index)
    $tabContent
        .children()
        .eq(index)
        .addClass('active')
        .siblings()
        .removeClass('active')
})

$tabBar.children().eq(index).trigger('click')

app3数据保存

我们要让正方形的位置保持不变,即便是刷新了,那么照样在原来的位置,除非鼠标点击,才会移动


修改app3的JS

代码语言:javascript
复制
import $ from 'jquery'
const $square = $('#app3 .square')
const localKey = 'app3.active'
const active = localStorage.getItem(localKey) === 'yes'

$square.toggleClass('active',active)

$square.on('click',()=>{
    if($square.hasClass('active')){
        $square.removeClass('active')
        localStorage.setItem(localKey,'no')
    }else{
        $square.addClass('active')
        localStorage.setItem(localKey,'yes')
    }
})

最小化知识点


修改app1.js

我们把html的内容,全部放到对应的JS中

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
const html = `
        <section id="app1">
            <div class="output">
                <span id="number">100</span>
            </div>
            <div class="actions">
                <button id="add1">+1</button>
                <button id="minus1">-1</button>
                <button id="mul2">*2</button>
                <button id="divide2">÷2</button>
            </div>
        </section>
`
const $element = $(html).prependTo($('body>.page'))
const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
const $number = $('#number')
const n = localStorage.getItem('n')


$number.text(n || 100)

$button1.on("click",()=>{
    let n = parseInt($number.text())
    n += 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button2.on("click",()=>{
    let n = parseInt($number.text())
    n -= 1
    localStorage.setItem('n',n)
    $number.text(n)
})

$button3.on("click",()=>{
    let n = parseInt($number.text())
    n *= 2
    localStorage.setItem('n',n)
    $number.text(n)
})

$button4.on("click",()=>{
    let n = parseInt($number.text())
    n /= 2
    localStorage.setItem('n',n)
    $number.text(n)
})

修改app2.js

app2.js

代码语言:javascript
复制
import $ from 'jquery'
const html = `
<section id="app2">
<ol class="tab-bar">
    <li>1</li>
    <li>2</li>
</ol>
<ol class="tab-content">
    <li>内容1</li>
    <li>内容2</li>
</ol>
</section>
`
const $element = $(html).appendTo($('body>.page'))
const $tabBar =  $('#app2 .tab-bar')
const $tabContent = $('#app2 .tab-content')
const localKey = 'app2.index'
const index =  localStorage.getItem(localKey) || 0

$tabBar.on('click','li',(e)=>{
    const $li = $(e.currentTarget)
    $li
        .addClass("selected")
        .siblings()
        .removeClass('selected')
    const index = $li.index()
    localStorage.setItem(localKey,index)
    $tabContent
        .children()
        .eq(index)
        .addClass('active')
        .siblings()
        .removeClass('active')
})

$tabBar.children().eq(index).trigger('click')

修改app3.js

app3.js

代码语言:javascript
复制
import $ from 'jquery'
const html = `
<section id="app3">
<div class="square"></div>
</section>
`
const $element = $(html).appendTo($('body>.page'))

const $square = $('#app3 .square')
const localKey = 'app3.active'
const active = localStorage.getItem(localKey) === 'yes'

$square.toggleClass('active',active)

$square.on('click',()=>{
    if($square.hasClass('active')){
        $square.removeClass('active')
        localStorage.setItem(localKey,'no')
    }else{
        $square.addClass('active')
        localStorage.setItem(localKey,'yes')
    }
})

修改app4.js

app4.js

代码语言:javascript
复制
import $ from 'jquery'
const html = `
<section id="app4">
<div class="circle"></div>
</section>
`
const $element = $(html).appendTo($('body>.page'))
const $circle = $('#app4 .circle')
$circle.on('mouseenter',()=>{
    $circle.addClass('active')
}).on('mouseleave',()=>{
    $circle.removeClass('active')
})

修改index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page"></div>
   <script src="main.js"></script> 
</body>
</html>

功能全部实现了,但是...是 辣鸡代码

MVC以不变应万变


使用MVC实现第一个模块

首先我们要做以下操作: - 所有数据相关的都放到m - 所有视图相关的都放到v - 其他的都放到c

index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page">
        <section id="app1"></section>
    </div>
   <script src="main.js"></script> 
</body>
</html>

main.js

代码语言:javascript
复制
import './reset.css'
import './global.css'
import './app1.css'
import './app2.css'
import './app3.css'
import './app4.css'
import x from './app1.js'
import './app2.js'
import './app3.js'
import './app4.js'

x.init('#app1')

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
const eventBus = $({})
// 数据相关都放到m
const m = {
    data: {
        n:parseInt(localStorage.getItem('n'))
    },
    create(){},
    delete(){},
    update(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('n',m.data.n)
    },
    select(){}
}
// 视图相关都放到v
const v = {
    el: null,
    html:`
    <div>
        <div class="output">
            <span id="number">{{ n }}</span>
        </div>
        <div class="actions">
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">*2</button>
            <button id="divide2">÷2</button>
        </div>
    </div>
`,
    init(container){
        v.el = $(container)
    },
    render(n){
        if(v.el.children.length !== 0) v.el.empty()
        $(v.html.replace('{{ n }}',n)).appendTo(v.el)
    }
}

// 其他都放到c
const c = {
    init(container){
        v.init(container)
        v.render(m.data.n)
        c.autoBindEvents()
        eventBus.on('m_updated',()=>{
            v.render(m.data.n)
        })
    },
    events:{
        'click #add1' : 'add',
        'click #minus1' : 'minus',
        'click #mul2' : 'mul',
        'click #divide2' : 'divide'
    },
    add(){
        m.update({n:m.data.n +1})
    },
    minus(){
        m.update({n:m.data.n -1})
    },
    mul(){
        m.update({n:m.data.n *2})
    },
    divide(){
        m.update({n:m.data.n /2})
    },
    autoBindEvents(){
        for(let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            v.el.on(part1,part2,value)
        }
    }
}

export default c

写好代码后,我们把代码折叠起来,会发现,代码里就三个对象,m v c


直接把刚才的MVC套用给第二个模块

我们还是要做以下操作: - 所有数据相关的都放到m - 所有视图相关的都放到v - 其他的都放到c

但是我们可以直接把写好的代码抄过来,再改

index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>曾老湿MVC</title>
</head>
<body>
    <div class="page">
        <section id="app1"></section>
        <section id="app2"></section>
    </div>
   <script src="main.js"></script> 
</body>
</html>

main.js

代码语言:javascript
复制
import './reset.css'
import './global.css'
import './app1.css'
import './app2.css'
import './app3.css'
import './app4.css'
import x from './app1.js'
import y from './app2.js'
import './app3.js'
import './app4.js'

x.init('#app1')
y.init('#app2')

app2.js

代码语言:javascript
复制
import $ from 'jquery'
const eventBus = $({})
// 数据相关都放到m
const localKey = 'app2.index'
const m = {
    data: {
        index: parseInt(localStorage.getItem(localKey) || 0)
    },
    create(){},
    delete(){},
    update(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('index',m.data.index)
    },
    select(){}
}
// 视图相关都放到v
const v = {
    el: null,
    html:(index) =>{
        return `
    <div>
    <ol class="tab-bar">
        <li class="${index === 0 ? 'selected' :''}" data-index="0">1</li>
        <li class="${index === 1 ? 'selected' :''}" data-index="1">2</li>
    </ol>
    <ol class="tab-content">
        <li class="${index === 0 ? 'active' :''}">内容1</li>
        <li class="${index === 1 ? 'active' :''}">内容2</li>
    </ol>
    </div>
`
    },
    init(container){
        v.el = $(container)
    },
    render(index){
        if(v.el.children.length !== 0) v.el.empty()
        $(v.html(index)).appendTo(v.el)
    }
}
// 其他都放到c
const c = {
    init(container){
        v.init(container)
        v.render(m.data.index)
        c.autoBindEvents()
        eventBus.on('m_updated',()=>{
            v.render(m.data.index)
        })
    },
    events:{
        'click .tab-bar li' : 'x'
    },
    x(e){
        const index = parseInt(e.currentTarget.dataset.index)
        m.update({index:index})
    },
    autoBindEvents(){
        for(let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            v.el.on(part1,part2,value)
        }
    }
}
export default c

使用类优化代码的Model

我们把公共的属性,抽出来

编程思想,事不过三: 同样的代码写三遍,就应该抽出来写成一个函数 同样的属性写三遍,就应该抽出来写成共用属性(原型或类) 同样的原型写三遍,就应该用集成

代价: 有的时候会造成继承层级太深,无法一下看懂代码 可以通过写文档,或者画图来解决


抽tmd

先创建一个base目录,然后在下面创建Model.js

代码语言:javascript
复制
class Model{
    create(){}
    delete(){}
    update(){}
    select(){}
}

所有的类都有增删改查四个属性

添加警告

代码语言:javascript
复制
class Model{
    create(){
        if(console && console.error)console.error('你还没有实现create')
    }
    delete(){
        if(console && console.error)console.error('你还没有实现delete')
    }
    update(){
        if(console && console.error)console.error('你还没有实现update')
    }
    select(){
        if(console && console.error)console.error('你还没有实现select')
    }
}

可以简化

代码语言:javascript
复制
class Model{
// ?. 可选链
    create(){
        console?.error?.('你还没有实现create')
    }
    delete(){
        console?.error?.('你还没有实现delete')
    }
    update(){
        console?.error?.('你还没有实现update')
    }
    select(){
        console?.error?.('你还没有实现select')
    }
}

最新语法,有很多编辑器都不支持。

model如何使用呢?

代码语言:javascript
复制
class Model{
    create(){
        console && console.error && console.error('你还没有实现create')
    }
    delete(){
        console && console.error && console.error('你还没有实现delete')
    }
    update(){
        console && console.error && console.error('你还没有实现update')
    }
    select(){
        console && console.error && console.error('你还没有实现select')
    }
}

const m = new Model()

m.create()
m.delete()
m.update()
m.select()

传递 data

代码语言:javascript
复制
class Model{
    constructor(options){
        this.data =  options.data
    }
    create(){
        console && console.error && console.error('你还没有实现create')
    }
    delete(){
        console && console.error && console.error('你还没有实现delete')
    }
    update(){
        console && console.error && console.error('你还没有实现update')
    }
    select(){
        console && console.error && console.error('你还没有实现select')
    }
}

export default Model

修改app1的JS

上面我们的Model完成了,那么就可以修改app1的js了

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
import Model from './base/Model.js'
const eventBus = $({})
// 数据相关都放到m

const m = new Model({
    data: {
        n:parseInt(localStorage.getItem('n'))
    },
    update: function(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('n',m.data.n)
    }
})

// 视图相关都放到v
const v = {
    el: null,
    html:`
    <div>
        <div class="output">
            <span id="number">{{ n }}</span>
        </div>
        <div class="actions">
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">*2</button>
            <button id="divide2">÷2</button>
        </div>
    </div>
`,
    init(container){
        v.el = $(container)
    },
    render(n){
        if(v.el.children.length !== 0) v.el.empty()
        $(v.html.replace('{{ n }}',n)).appendTo(v.el)
    }
}

// 其他都放到c
const c = {
    init(container){
        v.init(container)
        v.render(m.data.n)
        c.autoBindEvents()
        eventBus.on('m_updated',()=>{
            v.render(m.data.n)
        })
    },
    events:{
        'click #add1' : 'add',
        'click #minus1' : 'minus',
        'click #mul2' : 'mul',
        'click #divide2' : 'divide'
    },
    add(){
        m.update({n:m.data.n +1})
    },
    minus(){
        m.update({n:m.data.n -1})
    },
    mul(){
        m.update({n:m.data.n *2})
    },
    divide(){
        m.update({n:m.data.n /2})
    },
    autoBindEvents(){
        for(let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            v.el.on(part1,part2,value)
        }
    }
}

export default c

Model.js

代码语言:javascript
复制
class Model{
    constructor(options){
        ['data','update','create','delete','select'].forEach((key)=>{
            if(key in options){
                this[key] = options[key]
            }
        })
    }
    create(){
        console && console.error && console.error('你还没有实现create')
    }
    delete(){
        console && console.error && console.error('你还没有实现delete')
    }
    update(){
        console && console.error && console.error('你还没有实现update')
    }
    select(){
        console && console.error && console.error('你还没有实现select')
    }
}

export default Model

修改app2的JS

app2.js

代码语言:javascript
复制
import $ from 'jquery'
import Model from './base/Model.js'
const eventBus = $({})
// 数据相关都放到m
const localKey = 'app2.index'
const m = new Model({
    data: {
        index: parseInt(localStorage.getItem(localKey) || 0)
    },
    update(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('index',m.data.index)
    },
})
// 视图相关都放到v
const v = {
    el: null,
    html:(index) =>{
        return `
    <div>
    <ol class="tab-bar">
        <li class="${index === 0 ? 'selected' :''}" data-index="0">1</li>
        <li class="${index === 1 ? 'selected' :''}" data-index="1">2</li>
    </ol>
    <ol class="tab-content">
        <li class="${index === 0 ? 'active' :''}">内容1</li>
        <li class="${index === 1 ? 'active' :''}">内容2</li>
    </ol>
    </div>
`
    },
    init(container){
        v.el = $(container)
    },
    render(index){
        if(v.el.children.length !== 0) v.el.empty()
        $(v.html(index)).appendTo(v.el)
    }
}
// 其他都放到c
const c = {
    init(container){
        v.init(container)
        v.render(m.data.index)
        c.autoBindEvents()
        eventBus.on('m_updated',()=>{
            v.render(m.data.index)
        })
    },
    events:{
        'click .tab-bar li' : 'x'
    },
    x(e){
        const index = parseInt(e.currentTarget.dataset.index)
        m.update({index:index})
    },
    autoBindEvents(){
        for(let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            v.el.on(part1,part2,value)
        }
    }
}
export default c

使用类优化代码的View

代码语言:javascript
复制
class  View{
    constructor({el,html,render}){
        this.el = el
        this.html = html
        this.render = render
    }
}

export default View

修改app1的JS

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
import Model from './base/Model.js'
import View from './base/View.js'
const eventBus = $({})
// 数据相关都放到m

const m = new Model({
    data: {
        n:parseInt(localStorage.getItem('n'))
    },
    update: function(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('n',m.data.n)
    }
})

// 视图相关都放到v


// 其他都放到c
const c = {
    v:null,
    initV(){
        c.v = new View({
            el:c.container,
            html:`
            <div>
                <div class="output">
                    <span id="number">{{ n }}</span>
                </div>
                <div class="actions">
                    <button id="add1">+1</button>
                    <button id="minus1">-1</button>
                    <button id="mul2">*2</button>
                    <button id="divide2">÷2</button>
                </div>
            </div>
        `,
            render(n){
                if(c.v.el.children.length !== 0) c.v.el.empty()
                $(c.v.html.replace('{{ n }}',n)).appendTo(c.v.el)
            }
        })
    },
    init(container){
        c.container = container
        this.initV()
        c.v.render(m.data.n)
        c.autoBindEvents()
        eventBus.on('m_updated',()=>{
            c.v.render(m.data.n)
        })
    },
    events:{
        'click #add1' : 'add',
        'click #minus1' : 'minus',
        'click #mul2' : 'mul',
        'click #divide2' : 'divide'
    },
    add(){
        m.update({n:m.data.n +1})
    },
    minus(){
        m.update({n:m.data.n -1})
    },
    mul(){
        m.update({n:m.data.n *2})
    },
    divide(){
        m.update({n:m.data.n /2})
    },
    autoBindEvents(){
        for(let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            c.v.el.on(part1,part2,value)
        }
    }
}

export default c

合并V和C


修改app1的JS

app1.js

代码语言:javascript
复制
import $ from 'jQuery'
import Model from './base/Model.js'
const eventBus = $({})
// 数据相关都放到m

const m = new Model({
    data: {
        n:parseInt(localStorage.getItem('n'))
    },
    update: function(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem('n',m.data.n)
    }
})
// 其他都放到c
const view = {
    el: null,
    html:`
    <div>
        <div class="output">
            <span id="number">{{ n }}</span>
        </div>
        <div class="actions">
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">*2</button>
            <button id="divide2">÷2</button>
        </div>
    </div>
`,
    init(container){
        view.el = $(container)
        view.render(m.data.n)
        view.autoBindEvents()
        eventBus.on('m_updated',()=>{
            view.render(m.data.n)
        })
    },
    render(n){
        if(view.el.children.length !== 0) view.el.empty()
        $(view.html.replace('{{ n }}',n)).appendTo(view.el)
    },
    events:{
        'click #add1' : 'add',
        'click #minus1' : 'minus',
        'click #mul2' : 'mul',
        'click #divide2' : 'divide'
    },
    add(){
        m.update({n:m.data.n +1})
    },
    minus(){
        m.update({n:m.data.n -1})
    },
    mul(){
        m.update({n:m.data.n *2})
    },
    divide(){
        m.update({n:m.data.n /2})
    },
    autoBindEvents(){
        for(let key in view.events){
            const value = view[view.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            view.el.on(part1,part2,value)
        }
    }
}

export default view

修改app2的JS

app2.js

代码语言:javascript
复制
import $ from 'jquery'
import Model from './base/Model.js'
const eventBus = $({})
// 数据相关都放到m
const localKey = 'app2.index'
const m = new Model({
    data: {
        index: parseInt(localStorage.getItem(localKey) || 0)
    },
    update(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem(localKey,m.data.index)
    },
})
// 其他都放到c
const view = {
    el: null,
    html:(index) =>{
        return `
    <div>
    <ol class="tab-bar">
        <li class="${index === 0 ? 'selected' :''}" data-index="0">1</li>
        <li class="${index === 1 ? 'selected' :''}" data-index="1">2</li>
    </ol>
    <ol class="tab-content">
        <li class="${index === 0 ? 'active' :''}">内容1</li>
        <li class="${index === 1 ? 'active' :''}">内容2</li>
    </ol>
    </div>
`
    },
    render(index){
        if(view.el.children.length !== 0) view.el.empty()
        $(view.html(index)).appendTo(view.el)
    },
    init(container){
        view.el = $(container)
        view.render(m.data.index)
        view.autoBindEvents()
        eventBus.on('m_updated',()=>{
            view.render(m.data.index)
        })
    },
    events:{
        'click .tab-bar li' : 'x'
    },
    x(e){
        const index = parseInt(e.currentTarget.dataset.index)
        m.update({index:index})
    },
    autoBindEvents(){
        for(let key in view.events){
            const value = view[view.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            view.el.on(part1,part2,value)
        }
    }
}
export default view

重构View.js

我们合并之后,View的功能就多了,现在重构一下

app2.js

代码语言:javascript
复制
import $ from 'jquery'
import Model from './base/Model.js'
import View from './base/View.js'
const eventBus = $({})
// 数据相关都放到m
const localKey = 'app2.index'
const m = new Model({
    data: {
        index: parseInt(localStorage.getItem(localKey) || 0)
    },
    update(data){
        Object.assign(m.data,data)
        eventBus.trigger('m_updated')
        localStorage.setItem(localKey,m.data.index)
    },
})
// 其他都放到c
const init = (el)=>{
    const view = new View({
        el: el,
        eventBus: eventBus,
        data:m.data,
        html:(index) =>{
            return `
        <div>
        <ol class="tab-bar">
            <li class="${index === 0 ? 'selected' :''}" data-index="0">1</li>
            <li class="${index === 1 ? 'selected' :''}" data-index="1">2</li>
        </ol>
        <ol class="tab-content">
            <li class="${index === 0 ? 'active' :''}">内容1</li>
            <li class="${index === 1 ? 'active' :''}">内容2</li>
        </ol>
        </div>
    `
        },
        render(data){
            const index = data.index
            if(this.el.children.length !== 0) this.el.empty()
            $(this.html(index)).appendTo(this.el)
        },
        events:{
            'click .tab-bar li' : 'x'
        },
        x(e){
            const index = parseInt(e.currentTarget.dataset.index)
            m.update({index:index})
        },
    
    })
}
export default init

View.js

代码语言:javascript
复制
import $ from 'jquery'
class  View{
    //constructor({el,html,render,data,eventBus,events}){
    constructor(options){
        Object.assign(this,options)
        this.el = $(this.el)
        this.render(this.data)
        this.autoBindEvents()
        this.eventBus.on('m_updated',()=>{
            this.render(this.data)
        })
    }
    autoBindEvents(){
        for(let key in this.events){
            const value = this[this.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0,spaceIndex +1)
            const part2 = key.slice(spaceIndex)
            this.el.on(part1,part2,value)
        }
    }
}

export default View
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MVC设计模式
  • 先写一个意大利面条式的烂代码
  • 实现第一个模块-加减乘除按钮
  • 实现第二个模块-点击标签实现切换
  • 实现第三个模块-方块变成圆动画
  • 实现第四个模块-点击圆会渐变
  • app2数据保存
  • app3数据保存
  • 最小化知识点
  • MVC以不变应万变
  • 使用类优化代码的Model
  • 使用类优化代码的View
  • 合并V和C
相关产品与服务
堡垒机
腾讯云堡垒机(Bastion Host,BH)可为您的 IT 资产提供代理访问以及智能操作审计服务,为客户构建一套完善的事前预防、事中监控、事后审计安全管理体系,助力企业顺利通过等保测评。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档