- MVC设计模式
- 先写一个意大利面条式的烂代码
- 实现第一个模块-加减乘除按钮
- 实现第二个模块-点击标签实现切换
- 实现第三个模块-方块变成圆动画
- 实现第四个模块-点击圆会渐变
- app2数据保存
- app3数据保存
- 最小化知识点
- MVC以不变应万变
- 使用类优化代码的Model
- 使用类优化代码的View
- 合并V和C
-曾老湿, 江湖人称曾老大。 -笔者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个块 |
---|
<!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>
第一个块制作按钮 |
---|
<!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引入 |
---|
*{margin: 0;padding: 0;}
代码语言:javascript复制import './reset.css'
import './app1.css'

让第一个app占屏幕的四分之一 |
---|
#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 |
---|
<!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 |
---|
import './reset.css'
import './app1.css'
import $ from 'jQuery'
const $button1 = $('#add1')
const $button2 = $('#minus1')
const $button3 = $('#mul2')
const $button4 = $('#divide2')
添加事件-实现加法 |
---|
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)
})

添加事件-实现减法 |
---|
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)
})

添加事件-实现乘法 |
---|
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)
})

添加事件-实现除法 |
---|
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 |
---|
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)
})
实现第二个模块-点击标签实现切换
先添加两个列表 |
---|
<!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中引入 |
---|
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 |
---|
<!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>
监听点击事件 |
---|
import $ from 'jquery'
const $square = $('#app3 .square')
$square.on('click',()=>{
$square.toggleClass('active')
})
添加动画 |
---|
#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 |
---|
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'

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

加动画 |
---|
#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;
}
监听鼠标事件 |
---|
import $ from 'jquery'
const $circle = $('#app4 .circle')
$circle.on('mouseenter',()=>{
$circle.addClass('active')
}).on('mouseleave',()=>{
$circle.removeClass('active')
})
app2数据保存
我们要保证,用户将标签切换到2的时候,即便是刷新页面还在2
修改app2的JS |
---|
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 |
---|
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 |
---|
<!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