React+Redux实现简单的待办事项列表ToDoList


Posted in Javascript onSeptember 29, 2019

使用Redux做了一个简单的ToDoList待办事项列表,具体如下

这个例子也是源于Redux作者Dan Abramov的视频demo
还要特别说明一下
我还没有使用react-redux库进行解耦(可能以后加)
也没有拆分成多个文件等等优化
为了单纯的练习redux
适合初步学习redux的同学
本人学疏才浅,发现可以优化的地方或者问题还请大家指正,谢谢

功能样式

React+Redux实现简单的待办事项列表ToDoList

样子就是这样的
在输入框输入待办事项
功能很简单
鼠标点击Add或者键盘按下Enter输出
ShowAll显示全部待办事项
ShowActive显示未完成的待办事项(未划掉的)
ShowCrossed显示已完成的待办事项(划掉的)

配置文件

使用Webpack构建的文件夹如下

React+Redux实现简单的待办事项列表ToDoList

webpack.config.js配置文件

module.exports = {
 entry: {
 index: './src/js/entry.js'
 },
 output: {
 path: './static/dist/',
 publicPath: 'http://localhost:8080/static/dist/',
 filename: '[name].js'
 },
 module: {
 loaders: [
 {
 test: /\.js$/,
 loader: 'babel',
 exclude:/node_modules/,
 query: {
 presets: ['react', 'es2015']
 }
 },
 {
 test: /.less$/,
 loader: 'style!css!less'
 }
 ]
 }
}

package.json的依赖项

{
 "name": "react-demo",
 "version": "1.0.0",
 "description": "",
 "main": "webpack.config.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1",
 "diy": "webpack-dev-server --progress --colors --devtool sourcemap"
 },
 "author": "Payson",
 "license": "ISC",
 "devDependencies": {
 "babel-core": "^6.22.1",
 "babel-loader": "^6.2.10",
 "babel-preset-es2015": "^6.22.0",
 "babel-preset-react": "^6.22.0",
 "css-loader": "^0.26.1",
 "jquery": "^3.1.1",
 "less": "^2.7.2",
 "less-loader": "^2.2.3",
 "react": "^15.4.2",
 "react-dom": "^15.4.2",
 "react-redux": "^5.0.2",
 "redux": "^3.6.0",
 "style-loader": "^0.13.1",
 "webpack": "^1.14.0",
 "webpack-dev-server": "^1.16.2"
 }
}

html文件

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>React</title>
</head>
<body>
 <div id="root"></div>
 <script src="http://localhost:8080/static/dist/index.js"></script>
</body> 
</html>

脚本文件

没有细拆文件
直接写在入口文件entry.js了
注释就写在代码里了

require('../less/index.less'); //行间样式受限制不能添加伪类伪元素,所以还是添加了less(css)控制样式
import React from 'react';
import {Component} from 'react'
import ReactDom from 'react-dom';
import {createStore, combineReducers} from 'redux';

class ToDoList extends Component {
 addHandler(){ //添加待办事项的listener
 let Inp = this.refs.Inp; //获取真实DOM的输入value
 if(!Inp.value){ //如果没有输入值,直接返回
 return;
 }
 store.dispatch( //dispatch一个添加项目的action,并传入输入数据
 {
 type: 'ADD_ITEM',
 newItem: Inp.value
 }
 )
 Inp.value = ''; //提交后,清空输入
 Inp.focus(); //重置输入焦点
 }
 toggleHandler(item){ //Action Creator:负责提交切换中划线的action
 store.dispatch(
 {
 type: 'TOGGLE_ITEM',
 changeID: item.ID
 }
 );
 }
 showAllHandler(){ //Action Creator:负责showAll的action
 store.dispatch(
 {
 type: 'SET_FILTER',
 filter: 'SHOW_ALL'
 }
 );
 }
 showActiveHandler(){ //Action Creator:负责showActive的action
 store.dispatch(
 {
 type: 'SET_FILTER',
 filter: 'SHOW_ACTIVE'
 }
 );
 }
 showCrossedHandler(){ //Action Creator:负责showCrossed的action
 store.dispatch(
 {
 type: 'SET_FILTER',
 filter: 'SHOW_CROSSED'
 }
 );
 }
 render(){ //渲染结构样式
 let _this = this; //缓存this
 let state = store.getState(); //缓存store的快照--state
 let {list, option} = state; //解构赋值获取两个子state
 //list是一个数组,内部数组元素是对象表示每一个列表项
 //option是一个字符串,表示当先选择的选项
 switch(option){ //通过判断当前的option字符串来决定是否过滤list数组
 case 'SHOW_ACTIVE':
 list = list.filter(function(item){
 return !item.del;
 });
 break;
 case 'SHOW_CROSSED':
 list = list.filter(function(item){
 return item.del;
 });
 break;
 }
 document.body.addEventListener('keydown', function(e){
 if(e.which == 13){
 _this.addHandler();
 }
 }); //绑定键盘enter事件
 return (
 <div>
 <input type="text" ref="Inp"/> //设置ref属性为了获取真实DOM节点
 <button onClick={_this.addHandler.bind(_this)}>Add</button>
 <ul className="option">
 <li onClick={_this.showAllHandler.bind(_this)}>
 <span style={{textDecoration: option!='SHOW_ALL' ? 'underline' : 'none'}}>ShowAll</span>
 </li>
 <li onClick={_this.showActiveHandler.bind(_this)}>
 <span style={{textDecoration: option!='SHOW_ACTIVE' ? 'underline' : 'none'}}>ShowActive</span>
 </li>
 <li onClick={_this.showCrossedHandler.bind(_this)}>
 <span style={{textDecoration: option!='SHOW_CROSSED' ? 'underline' : 'none'}}>ShowCrossed</span>
 </li> //判断option字符串来决定三个选项的样式
 </ul>
 <ul className="list">
 {
 list.map(function(item, index){ //通过list数组map映射为虚拟DOM节点
 return <li key={index}>
 <span style={{textDecoration: item.del ? 'line-through': 'none'}} 
 onClick={_this.toggleHandler.bind(_this, item)}>{item.item}</span>
 </li>
 })
 }
 </ul>
 </div>
 )
 }
}
const list = (state = [], action) => { //list-reducer
 switch(action.type){
 case 'ADD_ITEM':
 return [
 ...state, 
 {
 item: action.newItem, //列表项内容
 ID: state.length, //列表项ID
 del: false //列表项是否已划掉
 }
 ];
 case 'TOGGLE_ITEM':
 return state.map((item)=>{
 return Object.assign({},item,{
 del: action.changeID == item.ID ? !item.del : item.del
 });
 });
 default:
 return state;
 }
}
const option = (state = 'SHOW_ALL', action) => { //option-reducer
 switch(action.type){
 case 'SET_FILTER':
 return action.filter;
 default:
 return state;
 }
}
const reducer = combineReducers({list, option}); //利用redux库API-combineReducers()合并reducer
const store = createStore(reducer); //利用redux库API-createStore()创建store
const render = () => { //自定义的渲染函数
 ReactDom.render(
 <ToDoList/>,
 document.getElementById('root')
 );
}
store.subscribe(render); //绑定render函数,每次state更新时执行
render(); //首次渲染

样式文件

index.less文件加一些样式控制

.option {
 list-style-type: none;
 padding: 0;
 margin-top: 5px;
 font-size: 13px;
 li {
 float: left;
 margin-right: 15px;
 span {
 cursor: pointer;
 font-weight: bold;
 }
 }
 &::after {
 content: '';
 display: block;
 clear: both;
 }
}
.list {
 li {
 span {
 &:hover {
 color: #f40;
 cursor: pointer;
 }
 &::selection {
 color: #000;
 background-color: #fff;
 }
 }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jscript之Open an Excel Spreadsheet
Jun 13 Javascript
Firefox下提示illegal character并出现乱码的原因
Mar 25 Javascript
通过继承IHttpHandle实现JS插件的组织与管理
Jul 13 Javascript
JavaScript字符串String和Array操作的有趣方法
Dec 18 Javascript
js返回上一页并刷新的多种实现方法
Feb 26 Javascript
CSS+JS实现点击文字弹出定时自动关闭DIV层菜单的方法
May 12 Javascript
浅析函数声明和函数表达式——函数声明的声明提前
May 03 Javascript
jQuery实现查找链接文字替换属性的方法
Jun 27 Javascript
详解使用vuex进行菜单管理
Dec 21 Javascript
Vue EventBus自定义组件事件传递
Jun 25 Javascript
基于JS抓取某高校附近共享单车位置 使用web方式展示位置变化代码实例
Aug 27 Javascript
修改NPM全局模式的默认安装路径的方法
Dec 15 Javascript
JS回调函数简单易懂的入门实例分析
Sep 29 #Javascript
在vue中根据光标的显示与消失实现下拉列表
Sep 29 #Javascript
js 下拉菜单点击旁边收起实现(踩坑记)
Sep 29 #Javascript
微信小程序 行的删除和增加操作实现详解
Sep 29 #Javascript
微信小程序 轮播图实现原理及优化详解
Sep 29 #Javascript
为nuxt项目写一个面包屑cli工具实现自动生成页面与面包屑配置
Sep 29 #Javascript
React-redux实现小案例(todolist)的过程
Sep 29 #Javascript
You might like
php正则
2006/07/07 PHP
Zend Studio 无法启动的问题解决方法
2008/12/04 PHP
php保存信息到当前Session的方法
2015/03/16 PHP
WordPress中创建用户角色的相关PHP函数使用详解
2015/12/25 PHP
php while循环控制的简单实例
2016/05/30 PHP
ThinkPHP开发--使用七牛云储存
2017/09/14 PHP
Yii2框架配置文件(Application属性)与调试技巧实例分析
2019/05/27 PHP
在修改准备发的批量美化select+可修改select时,在非IE下发现了几个问题
2007/01/09 Javascript
将HTMLCollection/NodeList/伪数组转换成数组的实现方法
2011/06/20 Javascript
十个迅速提升JQuery性能让你的JQuery跑得更快
2012/12/10 Javascript
微信中一些常用的js方法汇总
2015/03/12 Javascript
JavaScript实现图片DIV竖向滑动的方法
2015/04/25 Javascript
jquery简单实现幻灯片的方法
2015/08/03 Javascript
JS iFrame加载慢怎么解决
2016/05/13 Javascript
JavaScript 冒泡排序和选择排序的实现代码
2016/09/03 Javascript
js完整倒计时代码分享
2016/09/18 Javascript
webuploader模态框ueditor显示问题解决方法
2016/12/27 Javascript
vue2 如何实现div contenteditable=“true”(类似于v-model)的效果
2017/02/08 Javascript
Express本地测试HTTPS的示例代码
2018/06/06 Javascript
node.js到底要不要加分号浅析
2018/07/11 Javascript
NodeJS服务器实现gzip压缩的示例代码
2018/10/12 NodeJs
vue各种事件监听实例(小结)
2020/06/24 Javascript
[03:20]次级联赛厮杀超职业 现超级兵对拆世纪大战
2014/10/30 DOTA
python3.5仿微软计算器程序
2020/03/30 Python
解决Djang2.0.1中的reverse导入失败的问题
2019/08/16 Python
python+requests接口压力测试500次,查看响应时间的实例
2020/04/30 Python
python编写一个会算账的脚本的示例代码
2020/06/02 Python
惠普新加坡官方商店:HP Singapore
2020/04/17 全球购物
以下为Windows NT 下的32 位C++程序,请计算sizeof 的值
2016/12/07 面试题
教师考察材料范文
2014/06/03 职场文书
预备党员转正考核材料
2014/06/03 职场文书
网络营销策划方案
2014/06/04 职场文书
班级口号大全
2014/06/09 职场文书
违章停车检讨书
2014/10/21 职场文书
Python实现批量将文件复制到新的目录中再修改名称
2022/04/12 Python
Redis过期数据是否会被立马删除
2022/07/23 Redis