🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 为什么要做备忘清单 1. 最近经常忘事儿? 做个备忘清单吧, 这样你就可以忘得心安理得了... 2. 经验, 唯项目实战可得... 通过做项目, 把零碎的知识点整合起来 3. 项目就是门面, 是经验最好的证明 # 最终结果(1.0) 一开始, 什么都没有 ![1544939816596](https://box.kancloud.cn/d28689ab960b181376cfb1d7102c1103_665x142.png) 输入以后, 按回车, 或者点击按钮, 就可以看到添加后的清单 ![1544939954147](https://box.kancloud.cn/05fce2f16668502bf570c0ef478391d5_647x263.png) 新增的清单会放在最上面 ![1544940007373](https://box.kancloud.cn/42bec48534676d0b1a94a803204b83ae_703x332.png) 这是 1.0 版本, 后续会增加`编辑`,`删除`,`完成`等功能 # 资源准备 1. jquery 2. 阿里云矢量图标 # 搭建项目(文件夹 todo) 两个文件夹加一个文件 1. `css`文件夹 1. `js`文件夹 1. `index.html`文件 ![1544940550978](https://box.kancloud.cn/24afb6a7127ece85e5d36d02e66e28dc_199x152.png) # 搭建 html 结构(index.html) ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>备忘清单</title> </head> <body></body> </html> ``` 注意: 1. `lang`属性要写成`zh`, 不然 chrome 会总是问你, 要不要翻译 2. 把`tittle` 改成`备忘清单` 因为我们是伟大的前端工程师, 恪守`结构, 样式, 行为 三者分离`的金科玉律, 所以我们需要单独的新建 css 文件和 js 文件 既然我们已经有了`index.html`了, 那么现在就可以愉快的引入 css 和自定义的 js 了 ```html <link rel="stylesheet" href="css/style.css" /> <script src="js/index.js"></script> ``` 现在, 我们就可以修改 html 的结构了, 先看看最终效果图... ![1544940670798](https://box.kancloud.cn/fb151682a550f150e1c454cf0d5378f0_653x313.png) 看来我们需要一个`h1`标题, 一个`input`框来输入内容, 一个`button`来添加备忘 还需要一些`复选框`, 和`div`套`div`的内容展示, 当然还有后续会用到的两个图标... 多说无益, 撸起来!!! 先来一个总的容器(div), class 为`container` ```html <div class="container"></div> ``` 然后`container`里有一个标题... 我们就叫他`myTitle`吧 ```html <body> <div class="container"><h1 class="myTitle">我的备忘清单</h1></div> </body> ``` 标题下面是一个`input`框和一个蓝色的`button`... 我们用一个 class 为`add-task`的`div`把他们包起来 `emmet`快捷键 `.add-task>input[placeholder=写下你的备忘吧...][name=content]+button{添加备忘}` ```html <div class="container"> <h1 class="myTitle">我的备忘清单</h1> <div class="add-task"> <input type="text" placeholder="写下你的备忘吧..." name="content" /> <button>添加备忘</button> </div> </div> ``` 等等... `placeholder`属性是个什么鬼? > placeholder, HTML 5 <input> 属性,placeholder 属性提供可描述输入字段预期值的提示信息(hint)。该提示会在输入字段为空时显示,并会在字段获得焦点时消失。 看个例子 ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <style> body { text-align: center; } input { margin-top: 50px; width: 50%; height: 25px; border-radius: 10px; outline: none; } </style> </head> <body> <input type="text" placeholder="内容为空,自动显示, 输入内容则消失..." /> </body> </html> ``` 撤回来, 接着说... 下面是清单的列表 ![1544942731021](https://box.kancloud.cn/375d83dd5307eed0cb748076d65a6c6c_689x325.png) 我们用 div 套 div class`task-list`套 class`task-item` ```html <div class="task-list"><div class="task-item"></div></div> ``` `task-item`下面是 4 个`span` ![1544943333146](https://box.kancloud.cn/8cb1b76fa551ee2d0837574ced213752_666x64.png) 分别是, 一个`checkbox`, 一个文本, 两个图标 ```html <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"></span> <span class="iconfont-span"></span> </div> ``` 说到这, 我们需要两个图标, 一个是编辑, 一个是删除 去阿里图标库, 欢乐的购物吧, `let's go shopping!!!` [阿里巴巴矢量图标库](https://www.iconfont.cn/) 阿里巴巴推荐使用图标的三种方式 1. font-class ![1544943981442](https://box.kancloud.cn/fe4cd6d563dbcb7354351c2c75b184a4_327x250.png) 第一步:引入项目下面生成的 fontclass 代码: ```js <link rel="stylesheet" type="text/css" href="./iconfont.css"> ``` 第二步:挑选相应图标并获取类名,应用于页面: ```css <i class="iconfont icon-xxx"></i> ``` 2. symbol ![1544944740635](https://box.kancloud.cn/b47b0a72143dbb7b8c191242bca8075d_370x215.png) 第一步:引入项目下面生成的 symbol 代码: ```js <script src="./iconfont.js" /> ``` 第二步:加入通用 css 代码(引入一次就行): ```js <style type="text/css"> .icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style> ``` 第三步:挑选相应图标并获取类名,应用于页面: ```js <svg class="icon" aria-hidden="true"> <use xlink:href="#icon-xxx" /> </svg> ``` 3. unicode ![1544944890413](https://box.kancloud.cn/61004abb3260d0f8c37a78fc0ccbc8dc_323x176.png) 第一步:拷贝项目下面生成的 font-face ```js @font-face { font-family: 'iconfont'; src: url('iconfont.eot'); src: url('iconfont.eot?#iefix') format('embedded-opentype'), url('iconfont.woff') format('woff'), url('iconfont.ttf') format('truetype'), url('iconfont.svg#iconfont') format('svg'); } ``` 第二步:定义使用 iconfont 的样式 ```js .iconfont{ font-family:"iconfont" !important; font-size:16px;font-style:normal; -webkit-font-smoothing: antialiased; -webkit-text-stroke-width: 0.2px; -moz-osx-font-smoothing: grayscale; } ``` 第三步:挑选相应图标并获取字体编码,应用于页面 ```js <i class="iconfont">&#x33;</i> ``` 我们选择第一种方案, 只需要简单的几步 1. 拷贝资源(`iconfont.css`) ![1544945193291](https://box.kancloud.cn/e90dc715e921b61e15d2cca2664c6ba2_200x165.png) 2. 引入 css `<link rel="stylesheet" href="css/iconfont.css">` 3. 写入 html 代码 ```html <div class="task-list"> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"> <i class="iconfont icon-delete"></i> </span> <span class="iconfont-span"> <i class="iconfont icon-edit"></i> </span> </div> </div> ``` 现在完整版的 html 是这样的... ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <link rel="stylesheet" href="css/style.css" /> <link rel="stylesheet" href="css/iconfont.css" /> <script src="js/index.js"></script> <title>备忘清单</title> </head> <body> <div class="container"> <h1 class="myTitle">我的备忘清单</h1> <div class="add-task"> <input type="text" placeholder="写下你的备忘吧..." name="content" /> <button>添加备忘</button> </div> <div class="task-list"> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"> <i class="iconfont icon-del"></i> </span> <span class="iconfont-span"> <i class="iconfont icon-edit"></i> </span> </div> </div> </div> </body> </html> ``` 效果这样... ![1544945303532](https://box.kancloud.cn/344e884efc8115eddcd531a2eeaf7c4b_282x133.png) 嗯... 好丑... 丑就对了, 不然要 css 干什么? 最后, 注释是个好习惯 加完注释的样子... ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <link rel="stylesheet" href="css/style.css" /> <link rel="stylesheet" href="css/iconfont.css" /> <script src="js/index.js"></script> <title>备忘清单</title> </head> <body> <!-- 总容器开始 --> <div class="container"> <h1 class="myTitle">我的备忘清单</h1> <!-- 输入框和按钮开始 --> <div class="add-task"> <input type="text" placeholder="写下你的备忘吧..." name="content" /> <button>添加备忘</button> </div> <!-- 输入框和按钮结束 --> <!-- 清单列表开始 --> <div class="task-list"> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"> <i class="iconfont icon-del"></i> </span> <span class="iconfont-span"> <i class="iconfont icon-edit"></i> </span> </div> </div> <!-- 清单列表结束 --> </div> <!-- 总容器结束 --> </body> </html> ``` # css 布局 再看一眼最终效果... ![1544940670798](https://box.kancloud.cn/fb151682a550f150e1c454cf0d5378f0_653x313.png) 首先, 干掉默认样式 ```css * { margin: 0; padding: 0; } ``` 给个背景 需要用到`picpick`的取色器 ```css body { background: #00334b; color: #fff; } ``` 看下效果... ![1544945900678](https://box.kancloud.cn/efab9753b1034fcac54854a8cc74e873_278x109.png) 我们把标题居中吧... ```css h1 { text-align: center; } ``` ![1544945945711](https://box.kancloud.cn/b8557f99b7dedb14b3556892c71c08ff_1080x102.png) 让我们把总容器也居中吧, 不过先多加几个内容吧 ```html <div class="task-list"> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> </div> ``` ![1544946158333](https://box.kancloud.cn/cfaa05ca8c9d3df5590e07bae2d9598d_1080x200.png) 然后, 我们来设置居中 ```css .container { max-width: 600px; margin: 0 auto; background: red; } ``` ![1544946325556](https://box.kancloud.cn/380f40c66bb3cb7b7b962937e534ae3e_1080x191.png) `.task-item` 实在是太丑了, 需要美化一下了... ```css .task-item { background: #fff; color: #333; } ``` ![1544946596637](https://box.kancloud.cn/2eb915c65b714cd68b40deb611eb180f_1080x195.png) 从全红, 变成了全白... 还得改 ```css .task-item { background: #fff; color: #333; margin-bottom: 2px; cursor: pointer; } ``` 增加每个 item 的缝隙, 并且增加小手 ![1544946726991](https://box.kancloud.cn/17bd011e1c8224fc1eabf634dc028c75_1080x196.png) 把红色背景干掉吧... ```css .container { max-width: 600px; margin: 0 auto; /* background: red; */ } ``` ![1544946787334](https://box.kancloud.cn/c563fc8253971e7b101f8b069ac48075_1080x206.png) 鼠标经过 item 的时候, 应该暗一点... ```css .task-item:hover { background: #ddd; } ``` ![1544946912902](https://box.kancloud.cn/fb747ff96095c5c253ec7554b6c54773_1080x206.png) 嗯... item 应该更高一点, 顺便加一个圆角吧... ```css .task-item { background: #fff; color: #333; margin-bottom: 2px; cursor: pointer; padding: 10px; border-radius: 3px; } ``` ![1544947103402](https://box.kancloud.cn/667a50f7cfd3872ad66142069dad659e_1080x314.png) 这样就好看多了... 图标应该放到右边... ```css .iconfont-span { float: right; } ``` ![1544947306437](https://box.kancloud.cn/351475142f904b8588e193dcf6ad2e07_1080x300.png) 再隔开一点就好了... ```css .iconfont { margin-right: 10px; } ``` ![1544947432796](https://box.kancloud.cn/7fa83279377af592fa48cb744b5056d1_1080x310.png) 咦? 小铅笔和小垃圾篓的位置好像变了? ![1544947477837](https://box.kancloud.cn/38e11a9e02ddfd8158e35e8727b2f9ef_949x269.png) ![1544947491245](https://box.kancloud.cn/650b119f94b519d4682e18797cb07a8e_947x268.png) 一般都是编辑在左, 删除再右, 确实符合使用习惯, 但是, 为什么顺序会变呢? > html 代码是顺序执行的, 先看到了垃圾篓, 然后右浮动, 所有最右边被垃圾篓先占了... 把内容输入框和按钮也搞一下吧... 先把他们跟下面的宽度对齐... 那就需要设置这两个元素的宽度了 ```css input[type="text"] { float: left; width: 84%; margin-right: 1%; } .add-task button { width: 15%; } ``` 这样, 一个 85%, 一个 15%, 就可以排成一列, 并且和下面对齐了... ![1544949025721](https://box.kancloud.cn/7dc8c7324efd8043209bb1c3f8df2991_1080x316.png) 打扰了.... 为什么呢? 注意边框 ```css input[type="text"], .add-task button { border: 0; } ``` 这回可以了... ![1544949079739](https://box.kancloud.cn/0eb1a2b9f8bd007b2ca0efdf86557d94_1080x293.png) 给按钮一个蓝色背景吧, 还是需要取色... ```css .add-task button { background: #03aeff; } ``` ![1544949177781](https://box.kancloud.cn/5f1dc6c77347358aeed49e2e4f9bea52_1080x293.png) 想让 input 和 button 一样高... 可以给父级定一个高度, 让后让他俩都是 height100% ```css .add-task { height: 37px; } input[type="text"], .add-task button { border: 0; height: 100%; } ``` ![1544949332790](https://box.kancloud.cn/eaf8af54fdc55f86967449f0f258b1bd_1080x318.png) 看起来还不错, 不过需要加点间距... 我们可以给列表内容 div(`task-list`)加上 10px 的上下 margin... 当然也可以有其他增加间距的方式... ```css .task-list { margin: 10px 0; } ``` ![1544949568651](https://box.kancloud.cn/f8ad7d23b912a124d7c6b7afbd41f390_1080x320.png) 看起来还不错, 不过标题似乎太近了, 也加上 margin 吧... > 注意, 单纯的使用标签来给样式, 很容易`样式污染`, 所以尽量加上限制条件 ```css h1.myTitle { text-align: center; margin: 20px; } ``` ![1544949753593](https://box.kancloud.cn/efdfad0399c4a62095b8eb89f3d90bd1_1080x371.png) 趋于完美... input 框的文字太靠左了... 加点 padding... ![1544949831464](https://box.kancloud.cn/ed3d69cf2ea5157a4ae39fd084dd3232_947x322.png) ```css input[type="text"] { float: left; width: 84%; margin-right: 1%; padding: 10px; } ``` 这样应该就完美了... ![1544951132638](https://box.kancloud.cn/fd604c9706e55c88a45e151a1e750c6d_1080x373.png) 好吧, 心好累... 应该是 484 才对啊, 因为 504 是刚刚好啊... 现在加上 padding, 瓦特了... ![1544951211116](https://box.kancloud.cn/12ec147935ede2b51f93d9f8c664ab89_227x192.png) 又想增加 padding, 又想不改变 width, 怎么办呢? ```css input[type="text"] { float: left; width: 84%; margin-right: 1%; padding: 10px; -moz-box-sizing: border-box; /*Firefox3.5+*/ -webkit-box-sizing: border-box; /*Safari3.2+*/ -o-box-sizing: border-box; /*Opera9.6*/ -ms-box-sizing: border-box; /*IE8*/ box-sizing: border-box; } ``` 神奇的 box-sizing, 之前提过 ![1544951275415](https://box.kancloud.cn/04489464fc8f25de9a9ab64a3a4cf9a4_1080x369.png) 完美! 下面就是追求更完美的细节问题了... 如果你和我一样, 也有强迫症, 可以继续往下看... 首先, input 和 button 的圆角问题 所有的 input 和 button, 都应该圆角... 既然之前, 已经写过了, 那么直接合并就好 ```css input, button, .task-item { background: #fff; color: #333; margin-bottom: 2px; cursor: pointer; padding: 10px; border-radius: 3px; } ``` ![1544951921325](https://box.kancloud.cn/bb34a6b10bddb52b4312c45b16a78850_1080x366.png) 其次, task-item 的文字过于靠左 没啥说的, 直接加 margin-left ```css .task-content { margin-left: 5px; } ``` ![1544952015249](https://box.kancloud.cn/b3b6be743f5b1037cb7e367bd39dbe4c_1080x380.png) 产品经理说话了 > "input 输入框, 我想一开始是暗的, 鼠标悬停或者输入文字时是亮的..." 好吧, 这是我最后一次改样式... ```css input[type="text"] { background: #ddd; float: left; width: 84%; margin-right: 1%; padding: 10px; -moz-box-sizing: border-box; /*Firefox3.5+*/ -webkit-box-sizing: border-box; /*Safari3.2+*/ -o-box-sizing: border-box; /*Opera9.6*/ -ms-box-sizing: border-box; /*IE8*/ box-sizing: border-box; } ``` 加上背景属性即可 ![1544952407763](https://box.kancloud.cn/bbef289aa2b21e468f25e15a1af82863_1080x366.png) 悬停或者输入文本时高亮是吧... 那就是 hover 和 focus 的属性 ```css input[type="text"]:hover, input[type="text"]:focus { background: #eee; } ``` ![1544952537788](https://box.kancloud.cn/5362cedbd5518e38bbaa9a31f5a57667_1080x364.png) 是不是比刚才更亮了? > "input 输入框可以实现, 那么蓝色按钮没有理由不实现啊..." 好吧, 是我拿不动刀了, 还是你产品狗飘了? ![img](https://box.kancloud.cn/9dc3100c5190a2f199267bf5699b6c18_154x166.jpg) ```css .add-task button:hover { background: #57c6fb; } ``` ![1544952659202](https://box.kancloud.cn/285f5e27e9a8461f738c9e815ed2ffcc_1080x378.png) 截屏的时候, 小手截不到, 但是对比上图, 确实更亮了 另外, 输入内容时, 好像有个蓝色的边框... ![1544952802718](https://box.kancloud.cn/b71283622ec84b2fc8769e0a0da1985e_1080x363.png) 这是浏览器的默认样式, 干掉它!!! ```css * { margin: 0; padding: 0; outline: 0; } ``` 加上 outline 即可 烦人的蓝色边框不见了... ^\_^ ![1544952890380](https://box.kancloud.cn/37cd768eef8c8c21018f41499795b8a8_1080x375.png) 图标悬停的时候, 可以变得更黑吗? 不然我怎么知道这个图标可点? ```css .iconfont:hover { filter: drop-shadow(0 0 0 black); } ``` ![1544954883392](https://box.kancloud.cn/741bc6e7aece2e5c8c8592e4fe174e2a_1080x381.png) 看起来, 是粗了一点... ``` filter: drop-shadow(x偏移, y偏移, 模糊大小, 色值); ``` 例如: ``` filter:drop-shadow(5px 5px 10px black) ``` 什么? 什么? task-item 上的背景颜色, 来回切换时过于生硬? ![img](https://box.kancloud.cn/cb1fd6c21569b9485d9a069c99536dd9_100x100.png) 动画, 安排上... ```css * { margin: 0; padding: 0; outline: 0; -webkit-transition: background 200ms; -moz-transition: background 200ms; -ms-transition: background 200ms; -o-transition: background 200ms; transition: background 200ms; } ``` ![1544953000108](https://box.kancloud.cn/80d254a8aa2d0ab955c25f18a92dcbfa_1080x374.png) 搞定! ![img](https://box.kancloud.cn/e9863fd8665bbb9a66592b3d4e6354bd_400x274.jpg) **什么是动画???** ``` transition: property duration timing-function delay; ``` | 值 | 描述 | | -------------------------- | ----------------------------------- | | transition-property | 规定设置过渡效果的 CSS 属性的名称。 | | transition-duration | 规定完成过渡效果需要多少秒或毫秒。 | | transition-timing-function | 规定速度效果的速度曲线。 | | transition-delay | 定义过渡效果何时开始。 | 简单来说, `transition: background 200ms;` 就是 **转换背景颜色, 需要多长时间** 客户经理又说了... > 最后一个需求了, 能加点阴影就更有`质感`了... ![img](https://box.kancloud.cn/c38c88f9d97d52e3bebf947cd81b7649_300x187.jpg) **产品经理, 你全家都有`质感`...** 那么砍死产品经理以后, 我们可以说说阴影的事儿了... ``` box-shadow: h-shadow v-shadow blur spread color inset; ``` > 注释:box-shadow 向框添加一个或多个阴影。该属性是由逗号分隔的阴影列表,每个阴影由 2-4 个长度值、可选的颜色值以及可选的 inset 关键词来规定。省略长度的值是 0。 | 值 | 描述 | | ---------- | ---------------------------------------- | | _h-shadow_ | 必需。水平阴影的位置。允许负值。 | | _v-shadow_ | 必需。垂直阴影的位置。允许负值。 | | _blur_ | 可选。模糊距离。 | | _spread_ | 可选。阴影的尺寸。 | | _color_ | 可选。阴影的颜色。请参阅 CSS 颜色值。 | | inset | 可选。将外部阴影 (outset) 改为内部阴影。 | ```css -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); ``` > 内阴影, 水平 0, 垂直 1px, 模糊距离 2px; 阴影颜色 rgba(0, 0, 0, 0.1); ![1544954761746](https://box.kancloud.cn/0dd453bbb12944ae693fbb74f928b200_1080x376.png) 质感? 还好吧... 图个心安... ![img](https://box.kancloud.cn/2728a18fa005676323314ca077f5c286_240x240.jpg) 完整的 css 代码 ```css * { margin: 0; padding: 0; outline: 0; -webkit-transition: background 200ms; -moz-transition: background 200ms; -ms-transition: background 200ms; -o-transition: background 200ms; transition: background 200ms; } body { background: #00334b; color: #fff; } h1.myTitle { text-align: center; margin: 20px; } .container { max-width: 600px; margin: 0 auto; /* background: red; */ } input, button, .task-item { background: #fff; color: #333; margin-bottom: 2px; cursor: pointer; padding: 10px; border-radius: 3px; } .task-item:hover { background: #ddd; } .iconfont-span { float: right; } .iconfont { margin-right: 10px; } .iconfont:hover { filter: drop-shadow(0 0 0 black); } input[type="text"]:hover, input[type="text"]:focus { background: #eee; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } input[type="text"] { background: #ddd; float: left; width: 84%; margin-right: 1%; padding: 10px; -moz-box-sizing: border-box; /*Firefox3.5+*/ -webkit-box-sizing: border-box; /*Safari3.2+*/ -o-box-sizing: border-box; /*Opera9.6*/ -ms-box-sizing: border-box; /*IE8*/ box-sizing: border-box; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); } .add-task button { width: 15%; } input[type="text"], .add-task button { border: 0; height: 100%; } .add-task button { background: #03aeff; } .add-task button:hover { background: #57c6fb; } .add-task { height: 37px; } .task-list { margin: 10px 0; } .task-content { margin-left: 10px; } ``` # 书写 js 终于到了 jquery 时间... 我们今天先来 1.0 的版本功能 1. 输入内容在 input 框中回车, 或者点击蓝色按钮, 可以把内容插入备忘内容区 1. 最后插入的排在最上面 1. 如果文字内容过长, 展示时要有省略号 1. 页面刷新或者重启浏览器, 内容不丢失 第 0 步, **引入 jquery!** **引入 jquery!** **引入 jquery!** 重要的事情说三遍! 注意两者的顺序, 先引入 jquery, 再引入你自己的 index.js ![1544972943062](https://box.kancloud.cn/521adf47f3b1b2ea6dc8cd502572c707_977x379.png) 第一步, 先搭一个 jquery 的大致框架 1. 声明变量 1. 声明函数 1. 使用变量和函数完成代码逻辑 ```javascript $(function() { /* 声明变量 */ /* 声明函数 */ /* 逻辑代码 */ }); ``` 这什么都没写啊... 别着急, 正式开始 ```javascript $(function() { /* 声明变量 */ var aTaskList = []; // task数组, 用来保存task var nTaskIndex = 0; // task索引, 以后编辑task, 删除task, 都用得到 /* 声明函数 */ /* 逻辑代码 */ }); ``` 先完成第一个功能`输入内容在input框中回车, 或者点击蓝色按钮, 可以把内容插入备忘内容区` 咱们来分解一下 ![1544972629563](https://box.kancloud.cn/d8385176f953e129028538ebdccc365f_966x228.png) ```javascript /* 逻辑代码 */ // 获取输入框的内容-input-回车 // 输入框中, 按下回车, 获取内容 $("input[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13) { console.log($(this).val()); } }); ``` ![1544973037824](https://box.kancloud.cn/96eaa18f0069c0b834b6a6ba6dc5b688_1920x927.png) `keyCode`是什么? > `keyCode` 属性返回[onkeypress]()事件触发的键的值的字符代码(13 表示回车) 搞定第一个! ![1544973211087](https://box.kancloud.cn/0a51c01ed5ee92274775c085162c509d_968x191.png) 接着是点击提交按钮... ```javascript // 点击submit按钮, 获取输入框内容 $(".add-task button").on("click", function() { console.log($("input[name=content]").val()); }); ``` ![1544973278553](https://box.kancloud.cn/aa7f34ddfe601013899001bf2d46e06c_1920x927.png) 两种获取内容的方式都搞定了... ![1544973326326](https://box.kancloud.cn/963d69eea33796871c122a2b2020c548_961x203.png) 然后获取内容并展示 新建一个函数`addTask` ```javascript // 新增task function addTask(str) { // 获取内容 var taskHTML = ""; // 写入现有的html代码中 $(".task-list").prepend(taskHTML); } ``` 下载需要设置写入的内容, 就是文档中的这些内容 ```html <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span class="iconfont-span"><i class="iconfont icon-del"></i></span> <span class="iconfont-span"><i class="iconfont icon-edit"></i></span> </div> ``` 给变量`taskHTML`赋值 ```javascript function addTask(str) { // 获取内容 var taskHTML = ""; // 变量赋值 taskHTML += '<div class="task-item">'; taskHTML += '<span><input type="checkbox"/></span>'; taskHTML += '<span class="task-content">' + str + "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-del"> </i>'; taskHTML += "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-edit"> </i>'; taskHTML += "</span>"; taskHTML += "</div>"; // 写入现有的html代码中 $(".task-list").prepend(taskHTML); } ``` 同时, 我们也需要把之前的`获取内容,` 改为`添加内容` ```javascript // 获取输入框的内容-input-回车 // 输入框中, 按下回车, 获取内容 $("input[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13) { addTask($(this).val()); } }); // 点击submit按钮, 获取输入框内容 $(".add-task button").on("click", function() { addTask($("input[name=content]").val()); }); ``` 先试一下... ![1544974837366](https://box.kancloud.cn/d74255cd06cab9951035e46d8b566dde_829x428.png) 可以写进去, 成功了!!! ![1544979559788](https://box.kancloud.cn/2a436b1e517278e07f8364319df5f2d3_1058x211.png) 让我们多插几次! ![1544974922268](https://box.kancloud.cn/bf41d76d98547b2aab7baf4273e2a709_650x583.png) 发现一个问题, 每次插入以后, 原来 input 框里的内容还在, 新输入的话, 还需要把里面的内容先删了... 要是能增加以后, 自动清空 input 框就好了... 没有问题!!! ![img](https://box.kancloud.cn/dc441d0c0224f45b6988cce881a2d80c_240x240.jpg) 只需要稍微改几行代码就好了... ![1544975147291](https://box.kancloud.cn/49c11a422136eb33e95ab1cb611bb6c0_715x436.png) ![1544975188326](https://box.kancloud.cn/8706001ff78898970613adf96a4581bb_747x634.png) 自动清空, 毫无压力... 然而, 还有一个更严重的问题在等着大家... 当我小手一抖, 轻点刷新之后... ![1544975257977](https://box.kancloud.cn/8bcd62da1a6398c87dd454c2fea04041_799x379.png) 之前插入的内容全没了... 浏览器忘得比我快啊...![img](https://box.kancloud.cn/c2b6730d6bf9ac14ae2126c7bd7fdfc8_194x187.jpg) 数据持久化问题, 怎么解决呢? 方案一: 存数据库, 除非硬盘损毁, 和人为删库, 其他情况, 万无一失... 方案二: 存浏览器的 localStorage, 刷新, 重启, 只要浏览器不清缓存, 数据一直都在那里 我们使用方案二, 因为更快, 更简单 关于 localStorage, 你要知道... 1. 在 HTML5 中,新加入了一个 localStorage 特性,这个特性主要是用来作为本地存储来使用的,解决了 cookie 存储空间不足的问题(cookie 中每条 cookie 的存储空间为 4k),localStorage 中一般浏览器支持的是 5M 大小,这个在不同的浏览器中 localStorage 会有所不同。 2. localStorage 会可以将第一次请求的数据直接存储到本地,这个相当于一个 5M 大小的针对于前端页面的数据库,相比于 cookie 可以节约带宽 3. 目前所有的浏览器中都会把 localStorage 的值类型限定为 string 类型,这个在对我们日常比较常见的 JSON 对象类型需要一些转换 4. localStorage 在浏览器的隐私模式下面是不可读取的 5. localStorage 本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡 6. localStorage 与 sessionStorage 的唯一一点区别就是 localStorage 属于永久性存储,而 sessionStorage 属于当会话结束的时候,sessionStorage 中的键值对会被清空 7. 一般我们会将 JSON 存入 localStorage 中,但是在 localStorage 会自动将 localStorage 转换成为字符串形式, 这个时候我们可以使用 JSON.stringify()这个方法,来将 JSON 转换成为 JSON 字符串 8. 读取之后要将 JSON 字符串转换成为 JSON 对象,使用 JSON.parse()方法 了解一下语法吧... ```js localStorage.setItem("myCat", "Tom"); // 设置 ``` ```js let cat = localStorage.getItem("myCat"); // 获取 ``` ```js localStorage.removeItem("myCat"); // 删一项 ``` ```js localStorage.clear(); // 删所有 ``` 现在, 我们可以着手改代码了... 获取内容后, 除了要添加到 html 代码中, 同时需要压入数组, 把数组存起来, 方便刷新后使用 ```javascript $("input[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13) { addTask($(this).val()); aTaskList.push($(this).val()); // 压入数组 localStorage.setItem("aTaskList", aTaskList); // 更新缓存 $(this).val(""); } }); // 点击submit按钮, 获取输入框内容 $(".add-task button").on("click", function() { addTask($("input[name=content]").val()); aTaskList.push($("input[name=content]").val()); // 压入数组 localStorage.setItem("aTaskList", aTaskList); // 更新缓存 $("input[name=content]").val(""); }); ``` 那么, 刷新时, 我们需要一个把数据从缓存中取出, 并且展示出来的函数 ```javascript // 展示数据到内容区 function showTaskHTML() { var taskHTML = ""; var arr = localStorage.getItem("aTaskList"); for (var i = 0; i < arr.length; i++) { taskHTML += '<div class="task-item">'; taskHTML += '<span><input type="checkbox"/></span>'; taskHTML += '<span class="task-content">' + arr[i] + "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-del"> </i>'; taskHTML += "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-edit"> </i>'; taskHTML += "</span>"; taskHTML += "</div>"; } $(".task-list").html(taskHTML); } ``` 逻辑也比较简单, 从缓存中读取数据, 然后动态拼接 html, 修改 html 文件内容 我已经迫不及待的想试一下了... 当然, 别忘了调用... ![1544976910618](https://box.kancloud.cn/c5d094ed0dd102a6967d334d3319bfd9_437x196.png) 结果当然是悲剧了... ![img](https://box.kancloud.cn/892c26472196111af41ac4f12c824db6_200x200.jpg) ![1544977217156](https://box.kancloud.cn/1dec9ed5d10bb1d80302ae166fe6554e_714x321.png) 为什么会这样? 打印出来从缓存中获得的结果是`dddd`, 然后循环就悲剧了, `dddd`不是我最后一次的内容吗? ![img](https://box.kancloud.cn/ac0eaab208ac0843dd93fb700722123b_200x200.jpg) 骚年, 你忘了这么一句: > 1. 一般我们会将 JSON 存入 localStorage 中,但是在 localStorage 会自动将 localStorage 转换成为字符串形式, 这个时候我们可以使用 JSON.stringify()这个方法,来将 JSON 转换成为 JSON 字符串 > 1. 读取之后要将 JSON 字符串转换成为 JSON 对象,使用 JSON.parse()方法 localStorage 会把缓存起来的内容, 转成字符串, 所以我们要自己转 json 字符串, 完事儿自己转回来... 为了方便大家理解, 看个更刺激的 ![1544977568211](https://box.kancloud.cn/4e18924507b7b7b4bfc8b31533f2c7f9_1920x927.png) 数组转字符串就是这个下场!!!![img](https://box.kancloud.cn/a1579efe8b3f009a6c2147518bbf1aa8_299x300.jpg) 还有什么可说的, 改代码吧... 一共改了三个地方... ![1544977888136](https://box.kancloud.cn/79274622befe0e415544d30489f1f167_892x520.png) ![1544977907216](https://box.kancloud.cn/569db33747e3f7537971382b6c812135_1060x496.png) 结果`清空缓存`之后一刷新, 更热闹了... ![1544977958198](https://box.kancloud.cn/870792e0898ebba5b4b575cd14d294dd_1920x387.png) 想来也简单, 清空以后, 就没有数据了, 如何遍历呢, 看来还得在初始化变量时做文章... ```javascript /* 声明变量 */ // var aTaskList = []; // task数组, 用来保存task if (localStorage.getItem("aTaskList")) { var aTaskList = JSON.parse(localStorage.getItem("aTaskList")); showTaskHTML(); } else { var aTaskList = []; } ``` 数据展示也得改... ```javascript function showTaskHTML() { var taskHTML = ""; for (var i = 0; i < aTaskList.length; i++) { taskHTML += '<div class="task-item">'; taskHTML += '<span><input type="checkbox"/></span>'; taskHTML += '<span class="task-content">' + aTaskList[i] + "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-del"> </i>'; taskHTML += "</span>"; taskHTML += '<span class="iconfont-span">'; taskHTML += '<i class="iconfont icon-edit"> </i>'; taskHTML += "</span>"; taskHTML += "</div>"; } $(".task-list").html(taskHTML); } ``` 刷新, 重启都 ok, 除了... ![1544978388877](https://box.kancloud.cn/e756a2b2846e811af7559b51768c4880_676x311.png) ![1544978407740](https://box.kancloud.cn/ebbc82287aa80394721ccce3d865a029_677x318.png) 刷新之前, 4444 在最上面, 而刷新后 4444 就跑到了下面... 为什么?![img](https://box.kancloud.cn/05f8f020d2ed208951a755981f3d2f43_274x239.jpg) 因为数组有顺序啊, 小傻瓜!!! 你把`push`改成`unshift`再试试? 果然好了!!! ![img](https://box.kancloud.cn/9fb9ba6730d50d62c2575ef8b153132c_240x240.jpg) 不过当我看到这些的时候, 我的强迫症又犯了... ![1544978756155](https://box.kancloud.cn/fa603e4aff981501f03265e1793a32fc_859x915.png) 这两段代码, 真 TMD 的像!!! 不能忍! ![img](https://box.kancloud.cn/9abcc810e0c1cb0e2ab82ca6b57ba48d_184x210.jpg) 其实, 添加, 不就是, `把新写的代码, 加入缓存, 然后刷新`吗? 那就好办了... 直接把`addTask`干掉, 然后修改 input 回车和 button 点击的逻辑就可以了. ```javascript $("input[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13) { aTaskList.unshift($(this).val()); // 压入数组 localStorage.setItem("aTaskList", JSON.stringify(aTaskList)); // 更新缓存 $(this).val(""); showTaskHTML(); } }); // 点击submit按钮, 获取输入框内容 $(".add-task button").on("click", function() { aTaskList.unshift($("input[name=content]").val()); // 压入数组 localStorage.setItem("aTaskList", JSON.stringify(aTaskList)); // 更新缓存 $("input[name=content]").val(""); showTaskHTML(); }); ``` 什么? 什么? checkbox 和文字挨得太近? 把原来的 margin-left, 从 5px 改成 10px 就好了... ![1544979266132](https://box.kancloud.cn/fe90564b609e5e4915d1e0e5acda571c_690x448.png) ```css .task-content { margin-left: 10px; } ``` ![1544979502742](https://box.kancloud.cn/4b55c76a5dfe8375d8ddf137524236bc_677x462.png) 到了这里, 1.0 的版本, 可以告一段落了... 怎么可能? 你忘了这个!!! ![1544979664780](https://box.kancloud.cn/da4d00aef0808ebe02eb1a4141246606_671x188.png) 不过这真的是最后一个了... 文字过长容易出问题... ![1544979717770](https://box.kancloud.cn/bed218502aa42ea668b49b373f3798c8_698x494.png) ![1544979737070](https://box.kancloud.cn/8bf4465d453f2d7c5998a1b156e55101_720x565.png) 设置, 超过字数就显示省略号 ```javascript // 文字过多就显示省略号 function compressContent(str) { if (str.length >= 30) { return str.slice(0, 29) + "···"; } } ``` ```javascript // 获取输入框的内容-input-回车 // 输入框中, 按下回车, 获取内容 $("input[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13) { var taskContent = compressContent($(this).val()); aTaskList.unshift(taskContent); // 压入数组 localStorage.setItem("aTaskList", JSON.stringify(aTaskList)); // 更新缓存 $(this).val(""); showTaskHTML(); } }); // 点击submit按钮, 获取输入框内容 $(".add-task button").on("click", function() { var taskContent = compressContent($("input[name=content]").val()); aTaskList.unshift(taskContent); // 压入数组 localStorage.setItem("aTaskList", JSON.stringify(aTaskList)); // 更新缓存 $("input[name=content]").val(""); showTaskHTML(); }); ``` ![1544980166214](https://box.kancloud.cn/7d22a9419671a490741ee6751d279875_686x156.png) 完美!!! ![img](https://box.kancloud.cn/2e7d7445b77319148b0f0583ee7b6cfd_240x240.jpg) 最后贴出 js 的完整代码 ```javascript $(function() { /* 声明变量 */ if (localStorage.getItem("task_list")) { aTaskList = JSON.parse(localStorage.getItem("task_list")); } else { aTaskList = []; } showTask(); /* 声明函数 */ function showTask() { var taskHTML = ""; for (var i = 0; i < aTaskList.length; i++) { taskHTML += '<div class="task-item">'; taskHTML += '<span><input type="checkbox"></span>' + "\n"; taskHTML += '<span class="task-content">' + aTaskList[i] + "</span>"; taskHTML += '<span><i class="iconfont icon-del"></i></span>'; taskHTML += '<span><i class="iconfont icon-edit"></i></span>'; taskHTML += "</div>"; } $(".task-list").html(taskHTML); } /* 逻辑代码 */ $("[name=content]").on("keypress", function(ev) { if (ev.keyCode === 13 && compressContent($(this).val())) { aTaskList.unshift(compressContent($(this).val())); localStorage.setItem("task_list", JSON.stringify(aTaskList)); $(this).val(""); showTask(); } }); $(".add-task button").on("click", function() { if (compressContent($("[name=content]").val())) { aTaskList.unshift(compressContent($("[name=content]").val())); localStorage.setItem("task_list", JSON.stringify(aTaskList)); $("[name=content]").val(""); showTask(); } }); // 文字过多, 就显示省略号 function compressContent(str) { if (str.length >= 30) { return str.slice(0, 30) + "···"; } else { return str; } } }); ``` 完整 css ```css * { margin: 0; padding: 0; outline: none; -webkit-transition: background 200ms; -moz-transition: background 200ms; -ms-transition: background 200ms; -o-transition: background 200ms; transition: background 200ms; } body { background: #00334b; color: #fff; } h1.myTitle { text-align: center; margin: 20px; } .container { margin: 0 auto; /* background: red; */ max-width: 600px; } .task-item { background: #fff; color: #333; margin-bottom: 3px; cursor: pointer; padding: 10px; border-radius: 3px; } .task-item:hover { background: #ddd; } .iconfont { float: right; margin-right: 10px; } input[type="text"] { background: #ddd; float: left; width: 84%; margin-right: 1%; padding: 10px; -moz-box-sizing: border-box; /*Firefox3.5+*/ -webkit-box-sizing: border-box; /*Safari3.2+*/ -o-box-sizing: border-box; /*Opera9.6*/ -ms-box-sizing: border-box; /*IE8*/ box-sizing: border-box; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } input[type="text"]:focus, input[type="text"]:hover { background: #eee; } .add-task button { width: 15%; background: rgb(3, 174, 255); } .add-task button:hover { background: rgb(77, 195, 251); } input[type="text"], .add-task button { border: 0; height: 100%; } .add-task { height: 37px; } .task-list { margin: 10px 0; } input, button { border-radius: 3px; } .task-content { margin-left: 5px; } .iconfont:hover { filter: drop-shadow(0 0 0 black); } ``` 完整 html ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <link rel="stylesheet" href="css/style.css" /> <link rel="stylesheet" type="text/css" href="css/iconfont.css" /> <script src="js/jquery.js"></script> <script src="js/index.js"></script> <title>备忘清单</title> </head> <body> <!-- 总容器开始 --> <div class="container"> <h1 class="myTitle">我的备忘清单</h1> <!-- 输入框和按钮开始 --> <div class="add-task"> <input type="text" placeholder="写下你的备忘吧..." name="content" /> <button>添加备忘</button> </div> <!-- 输入框和按钮结束 --> <!-- 清单列表开始 --> <div class="task-list"> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span><i class="iconfont icon-del"></i></span> <span><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span><i class="iconfont icon-del"></i></span> <span><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span><i class="iconfont icon-del"></i></span> <span><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span><i class="iconfont icon-del"></i></span> <span><i class="iconfont icon-edit"></i></span> </div> <div class="task-item"> <span><input type="checkbox" /></span> <span class="task-content">item content 1</span> <span><i class="iconfont icon-del"></i></span> <span><i class="iconfont icon-edit"></i></span> </div> </div> <!-- 清单列表结束 --> </div> <!-- 总容器结束 --> </body> </html> ```