MVC设计模式要点(一)基本功能实现

116 阅读2分钟

project from jirengu.com fangyinghang Frontend class

demo实现的功能:

111.png

新建src文件夹

  • index.html

把meta view-port改为taobao标准版:

搜索m.taobao.com > F12 > 元素 > head > meta name="viewport" > 右键复制 > 复制 outerHTML > 粘贴到index里面

<script src="main.js"></script>

建立服务器: vscode打开终端 > parcel src/index.html

  • main.js
  1. 创建4个div,后期会改为section:

快速输入div id=""的方法是#app1+#app2+#app3+#app4,然后按Tab
快速输入div class=""的方法是.app1+.app2+.app3+.app4,然后按Tab

<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时作为索引
            <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">
        <div class="circle"></div>
    </section>
    </div>
    <script src="main.js"></script>
</body>
  1. 引入css的方法:

在index的head标签里面,写<link rel="stylesheet" href="app1.css">
在main.js里面,写import './app1.css'

  1. app1.css里面的内容:
#app1{}
#app1 .output{}
#app1 .action{}
  1. reset.css的引入在main.js里面加一行import './reset.css',其里面的内容:
*{margin:0;padding:0}
  1. 安装jquery的方法,在终端中输入如下命令:
yarn init
yarn add jquery
  1. 引入jquery的方法,在main.js中,增加一行import $ from 'jquery'

  2. 获取到button,需要使用div的id索引到每个button,

const $button1 = $('#add1');
const $button2 = $('#minus1');
const $button3 = $('#mul2');
const $button4 = $('#divide2');
const $number = $('#number');
  1. 点击事件:事件处理器(event handler)
target.onclick = functionRef;
  • functionRef 是一个函数名称,或一个 函数表达式。该函数接收 MouseEvent对象作为其唯一参数。在函数内,this是触发当前事件的元素(同时匹配 event.currentTarget)。
  • MouseEvent对象有单击click双击dblclick松开Mouseup按下Mousedown
  • 函数表达式的语法为:
let function_expression = function [name]([param1[, param2[ , ..., paramN]]]) {
   statements
};
  • name函数名称。可被省略,此种情况下的函数是匿名函数(anonymous)。 函数名称只是函数体中的一个本地变量。
  • paramN被传递给函数的一个参数名称。
  • statements 构成函数体的语句。
$button1.on('click',() => {
    let n = parseInt($number.text());
    n += 1;
    localStorage.setItem('n',n)  //把每次运算的结果,保存到本地,确保用户刷新时,数值不变
    $number.text(n);
});

按照上面的思路,把-1,x2,/2都实现,但是埋下一个伏笔,此时代码已经有重复的情况,有优化的空间。

  1. 计算的过程
const n = localStorage.getItem('n');
$number.text(n || 100);
  1. 滚动条的宽度14-19px左右;

  2. 模块化:把一个功能放在一个模块里

import "./reset.css";
import './global.css';
import './app1.css';   //可以挪到app1.css的文件里面
import './app1.js';
import "./app2.css"    //可以挪到app2.css的文件里面
import './app2.js'
  1. 实现app2的功能:
import $ from "jquery";               //不会多次加载jquery
const $tabBar = $("#app2 .tab-bar");  //定义 $tabBar 是app2里面的tab-bar
const $tabContent = $('#app2 .tab-content')

//监听两个li的父元素<ol class="tab-bar"> 点击事件,此为事件委托
$tabBar.on("click", "li", e =>{  
    const $li = $(e.currentTarget);
    const index = $li.index();     //看一下点击的li排行老几
    $tabContent.children().eq(index).css({display:'block'})
});

12.1 如何知道一个元素在他的兄弟中排行老几,就是遍历他的兄弟,然后看第几个兄弟跟他是一样的,jqurey内置了上述的这个方法($li.index()),首先拿到用户点击的这个元素,e.target是用户点击的元素,而e.currentTarget才是开发者想监听的元素,也就是此例中的li

12.2 获取到了第几个以后,就可以把ol class="tab-content"下面的(children)两个li,等于第index个(.eq(index))对应display:block(.css({display:'block'})),同时通过链式操作找到他的兄弟(.siblings().css({display:'none'})),完整的代码如下:

$tabContent.children().eq(index).css({display:'block'}).siblings().css({display:'none'})
//找到tabContent的儿子们,等于第index个的css变成display:block,同时他的兄弟的css变成displaynone

12.3 但是上面的.css().show().hide()这三个API,不能使用,需要替换为.addClass('active')removeClass('active')这样就避免JS跨界去管样式的情况,只由CSS去自己解决样式问题,各干各的事。

$tabContent.children().eq(index).addClass('active').siblings().removeClass('active')
#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{  //如果li拥有active类,
    display:block;
}

12.4 以上3步(12.1-12.3)的思想是样式与行为分离,JS只管功能,CSS只管样式;

12.5 实现背景色切换功能:

$li.addClass('selected').siblings().removeClass('selected')
#app2 .tab-bar > li.selected{
    background: yellow;
    color: white;
}

12.6 刚进入页面时,既不显示1,也不显示2,那就预先初始化一个触发click的tab:

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

12.7 添加数据保存功能:

const localKey = 'app2.index'
const index = localStorage.getItem('localKey') || 0  //保底值为0

const index = $li.index();
localStorage.setItem(localKey, index)  //设置localKey 为index

$tabBar.children().eq(index).trigger('click')
  1. 实现app3的功能:
import $ from 'jquery'
import './app3.css'

const $square = $('#app3 .square')
const localKey = 'app3.active'
// 有三种情况yes,no,undefined(默认)
//const active = localStorage.getItem(localKey) === 'yes' ?true :false
const active = localStorage.getItem(localKey) === 'yes'

if(active){
    $square.addClass('active')
}else{
    $square.removeClass('active')
}
//以上三行代码也等价于 `$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')
    }
})
#app3{
};
#app3 .square{
    border: 1px solid grey;
    margin-top:10vw;
    margin-left:10vw;
    width:10vw;
    height: 10vw;
};
#app3 .square.active{
    transform:translateX(15vw);  //往右平移
}
  1. 实现app4的功能:
import $ from 'jquery'
import './app4.css'

const $circle = $('app4 .circle')

$circle.on('mouseenter',()=>{
    $circle.addClass('active')
}).on('mouseleave',()={
    $circle.removeClass('active')
})
#app4{
}
@keyframes change{
 0%{background: red}
 100%{background: blue}

}
#app4 .circle{
    width: 30vw;
    height: 30vw;
    border-radius: 50%;
}
#app4 .circle.active{
    animation: change 1s infinite alternate linear;
}