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 相关文章推荐
Javascript函数的参数
Jul 16 Javascript
Javascript实现快速排序(Quicksort)的算法详解
Sep 06 Javascript
jquery+php实现滚动的数字特效
Nov 29 Javascript
jQuery密码强度验证控件使用详解
Jan 05 Javascript
详解react-router如何实现按需加载
Jun 15 Javascript
详解使用webpack打包编写一个vue-toast插件
Nov 08 Javascript
使用vue如何构建一个自动建站项目
Feb 05 Javascript
当vue路由变化时,改变导航栏的样式方法
Aug 22 Javascript
前端防止用户重复提交js实现代码示例
Sep 07 Javascript
从零开始用electron手撸一个截屏工具的示例代码
Oct 10 Javascript
layui layer select 选择被遮挡的解决方法
Sep 21 Javascript
JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例
Nov 19 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中的strpos使用示例
2014/02/27 PHP
深入解析WordPress中加载模板的get_template_part函数
2016/01/11 PHP
PHP中调用C/C++制作的动态链接库的教程
2016/03/10 PHP
Yii+upload实现AJAX上传图片的方法
2016/07/13 PHP
js function使用心得
2010/05/10 Javascript
JS上传前预览图片实例
2013/03/25 Javascript
js获取 type=radio 值的方法
2014/05/09 Javascript
jQuery简单实现网页选项卡特效
2014/11/24 Javascript
javascript数组输出的两种方式
2015/01/13 Javascript
JS上传组件FileUpload自定义模板的使用方法
2016/05/10 Javascript
JavaScript职责链模式概述
2016/09/17 Javascript
基于jquery实现二级联动效果
2017/03/30 jQuery
nodejs socket实现的服务端和客户端功能示例
2017/06/02 NodeJs
浅谈vue.js导入css库(elementUi)的方法
2018/03/09 Javascript
浅谈Angular HttpClient简单入门
2018/05/04 Javascript
js遍历添加栏目类添加css 再点击其它删除css【推荐】
2018/06/12 Javascript
JS与SQL方式随机生成高强度密码示例
2018/12/29 Javascript
详解如何使用nvm管理Node.js多版本
2019/05/06 Javascript
Vue路由管理器Vue-router的使用方法详解
2020/02/05 Javascript
jQuery实现图片切换效果
2020/10/19 jQuery
[01:33:07]VGJ.T vs Newbee Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
Python实现堆排序的方法详解
2016/05/03 Python
Python设置默认编码为utf8的方法
2016/07/01 Python
python 生成器生成杨辉三角的方法(必看)
2017/04/10 Python
详解Python如何生成词云的方法
2018/06/01 Python
django admin后台添加导出excel功能示例代码
2019/05/15 Python
python实现超市商品销售管理系统
2019/10/25 Python
django框架使用views.py的函数对表进行增删改查内容操作详解【models.py中表的创建、views.py中函数的使用,基于对象的跨表查询】
2019/12/12 Python
零基础学python应该从哪里入手
2020/08/11 Python
python3获取控制台输入的数据的具体实例
2020/08/16 Python
英国景点门票网站:attractiontix
2019/08/27 全球购物
2014年大班元旦活动方案
2014/02/26 职场文书
我的画教学反思
2014/04/28 职场文书
销售代理协议书
2014/09/30 职场文书
2014年职称评定工作总结
2014/11/26 职场文书
长征观后感
2015/06/09 职场文书