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 相关文章推荐
谷歌浏览器 insertCell与appendChild的区别
Feb 12 Javascript
JS二维数组的定义说明
Mar 03 Javascript
jquery自动填充勾选框即把勾选框打上true
Mar 24 Javascript
jquery动态调整div大小使其宽度始终为浏览器宽度
Jun 06 Javascript
Node.js中如何合并两个复杂对象详解
Dec 31 Javascript
js仿新浪微博消息发布功能
Feb 17 Javascript
footer定位页面底部(代码分享)
Mar 07 Javascript
react-native DatePicker日期选择组件的实现代码
Sep 12 Javascript
深入理解Vue2.x的虚拟DOM diff原理
Sep 27 Javascript
在vue项目中引入高德地图及其UI组件的方法
Sep 04 Javascript
vue使用keep-alive保持滚动条位置的实现方法
Apr 09 Javascript
file-loader打包图片文件时路径错误输出为[object-module]的解决方法
Jan 03 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/12/21 PHP
比较详细PHP生成静态页面教程
2012/01/10 PHP
提高Laravel应用性能方法详解
2019/06/24 PHP
JSQL SQLProxy 的 php 版本代码
2010/05/05 Javascript
Jquery实现的tab效果可以指定默认显示第几页
2013/10/16 Javascript
使用JS取得焦点(focus)元素代码
2014/03/22 Javascript
基于jQuery实现复选框的全选 全不选 反选功能
2014/11/24 Javascript
详谈LABJS按需动态加载js文件
2015/05/07 Javascript
非常棒的jQuery图片轮播效果
2016/04/17 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
JavaScript随机打乱数组顺序之随机洗牌算法
2016/08/02 Javascript
js从外部获取图片的实现方法
2016/08/05 Javascript
JavaScript数组去重由慢到快由繁到简(优化篇)
2016/08/26 Javascript
原生js实现电商侧边导航效果
2017/01/19 Javascript
JavaScript实现经纬度转换成地址功能
2017/03/28 Javascript
关于页面刷新vuex数据消失问题解决方案
2017/07/03 Javascript
vue中的非父子间的通讯问题简单的实例代码
2017/07/19 Javascript
详解用node搭建简单的静态资源管理器
2017/08/09 Javascript
iconfont的三种使用方式详解
2018/08/05 Javascript
[42:56]VGJ.S vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python urlopen()函数 示例分享
2014/06/12 Python
Python代码的打包与发布详解
2014/07/30 Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
2016/07/11 Python
一文总结学习Python的14张思维导图
2017/10/17 Python
用python的requests第三方模块抓取王者荣耀所有英雄的皮肤实例
2017/12/14 Python
python实现词法分析器
2019/01/31 Python
python中的itertools的使用详解
2020/01/13 Python
Python定时从Mysql提取数据存入Redis的实现
2020/05/03 Python
在HTML5 Canvas中放入图片和保存为图片的方法
2014/05/03 HTML / CSS
KEEN美国官网:美国人气户外休闲鞋品牌
2021/03/09 全球购物
巧克力蛋糕店创业计划书
2014/01/14 职场文书
幼儿园老师个人总结
2015/02/28 职场文书
同学聚会通知短信
2015/04/20 职场文书
简历中的自我评价应该这样写!
2019/07/12 职场文书
英国数字版游戏销量周榜公布 《小缇娜的奇幻之地》登顶
2022/04/03 其他游戏
二维码条形码生成的JavaScript脚本库
2022/07/07 Javascript