1. 程式人生 > >TodoList React+NODE連結mysql資料庫完成增刪改查DEMO

TodoList React+NODE連結mysql資料庫完成增刪改查DEMO

遇到的難點:

跨域:原因是通過gulp啟動的React專案等於是從本地路徑訪問網路的NODE於是會造成跨域問題

解決:在後面加上了跨域訪問設定

 res.writeHead(200, {'Content-Type': 'text/plain; charset=utf8','Access-Control-Allow-Origin':"*"});

TodoList

var React = require("react");
var ReactDOM = require("react-dom");
// var mysql = require('mysql');
var axios = require("axios")

// var connection = mysql.createConnection({
//   host     : 'localhost',
//   user     : 'root',
//   password : '1234',
//   database : 'goods'
// });
// connection.connect();
// var conn = new Promise(resolve=>{
// 	connection.query('SELECT * from goods', function (error, results, fields) {
// 		if (error) throw error;
// 		console.log('The solution is: ', results);
// 		resolve(results);
// 	});
// })

/*這只是子元件*/
/*這個是設定的自動增長ID*/
var ids=0;
class todolist extends React.Component{
	constructor(){
		super();
		this.state={
			/*儲存任務的陣列*/
			arr:[],
			/*完成任務數的記錄變數*/
			wancheng:0,
			/*未完成。。。*/
			weiwan:0,
			/*span樣式名的記錄變數*/
			className12:"todolist_li",
		}

	}
	//find
	find(){
		axios.get("http://192.168.1.104:8080/find").then(
			value=>{
				// alert("success");
				// console.log(value);
				this.state.arr=value.data;
				this.state.weiwan=value.data.length;
				this.setState(this.state);
			}
			,error=>{console.log(error)});
		// axios.get("http://192.168.1.104:8080/findLIST").then(
		// 	value=>{
		// 		// console.log(value.data)
		// 		this.state.arr=value.data;
		// 		// this.state.arr.forEach(function(item){
		// 		// 	item.completed=false;
		// 		// })
		// 		this.state.weiwan=value.data.length;
		// 		this.setState(this.state);
		// 	}
		// 	,error=>{console.log("error")});
	}
	//delete
	delete(id){
		//http://192.168.1.104:8080/delete
		let self = this;
		axios.get("http://192.168.1.104:8080/delete",{params:{id:id}}).then(
			value=>{
				// console.log("success")
				self.find();
			}
			,error=>{console.log("error")});
	}
	//update
	update(item){
		axios.get("http://192.168.1.104:8080/update",{params:{id:item.id,completed:item.completed,title:item.title,bol:item.bol}}).then(
			value=>{
				this.find();
			}
			,error=>{console.log("error")});
	}
	//add
	add(title){
		axios.get("http://192.168.1.104:8080/add",{params:{title:title}}).then(
			value=>{
				this.find();
			}
			,error=>{console.log("error")});
	}
	componentDidMount(){
		// conn.then(value=>{alert("success")})
		this.find();
	}
	/*增加任務的方法,有父元件index.jsx用refs呼叫傳值val*/
	/*val是input任務輸入框的value*/
	onAdd(val){
		// this.state.arr.push({title:val,completed:false,id:ids++,bol:true})
		this.add(val);
		this.setState(this.state);
		this.state.zongshu=(this.state.arr).length;
		this.state.weiwan=this.state.zongshu-this.state.wancheng
	}
	/*checkbox的觸發事件,該事件把標記完成是否的completed屬性反轉*/
	onCheck(event){
		/*首先獲取CheckBox的value值也就是index陣列下標*/
		let index = event.target.value;
		/*把標記取反,用來改變記錄,等下用來標記span的樣式*/
		this.state.arr[index].completed=!(this.state.arr[index].completed);
		// this.update(this.state.arr[index]);
		this.setState(this.state);
		// console.log(this.state.arr)
		/*記錄未完成和完成的個數*/
		/*假如是完成了的*/
		if(this.state.arr[index].completed){
			/*那它的完成數就在基礎上加一*/
			this.state.wancheng=this.state.wancheng+1;
			/*任務總數減完成數=未完成數*/
			this.state.weiwan=this.state.arr.length-this.state.wancheng
		}else{
			/*反之,假如已將被選為完成,那麼就標記為未完成*/
			/*重新記錄未完成個數*/
			this.state.wancheng=this.state.wancheng-1;
			this.state.weiwan=this.state.arr.length-this.state.wancheng
		}
		/*更新該資料,它會自動呼叫render方法重新把值渲染到檢視*/
		this.setState(this.state)
	}
	/*刪除任務方法*/
	deleteVal(){
		/*把原來的方法備份*/
		let arr = this.state.arr;
		/*從屁股刪起刪除*/
		for(let i=arr.length-1;i>=0;i--){
			/*假如標記為true,代表已完成,就幹掉他*/
			if (arr[i].completed) {
				/*splice刪除方法,第一個引數是從第幾位開始刪,刪幾條*/
				// this.state.arr.splice(i,1);
				//後臺資料庫
				this.delete(this.state.arr[i].id);
			}
			/*把完成的任務數歸零*/
			this.state.wancheng=0;
			/*重新計算未完成數*/
			this.state.weiwan=this.state.arr.length-this.state.wancheng
		}
		/*檢視重新渲染*/
		this.setState(this.state)
	}

	/*轉換顯示span和輸入input的方法*/
	onInput(event){
		/*觸發該方法,可以通過以下的方法獲取到DOM物件本體obj*/
		event = event ? event : window.event;
		var obj = event.srcElement ? event.srcElement : event.target;
		//這時obj就是觸發事件的物件,可以使用它的各個屬性
		//還可以將obj轉換成jquery物件,方便選用其他元素
		/*這個obj就是觸發方法的span或者input*/
		/*然後獲取它的同級上一個元素,就是checkbox DOM節點,該節點記錄了該list的index下標*/
		let index = obj.previousSibling.value
		/*獲取該下表的bol標記,並取反*/
		let bol = !(this.state.arr[index].bol);
		/*重新設定該屬性為原來的反值*/
		this.state.arr[index].bol=bol;
		console.log(obj.nodeName);
		if (obj.nodeName=='INPUT') {
			this.update(this.state.arr[index]);
		}

		/*重新渲染*/
		this.setState(this.state)
		// console.log(this.state.arr[index].bol);
	}
	/*這個方法是讓改變後的input可以以改變item.title的值呼叫的是onChange方法*/
	onInputChange(event){
		/*同樣跟上面一樣,獲取到該物件,然後獲取上一個DOM,然後獲取index*/
		event = event ? event : window.event;
		var obj = event.srcElement ? event.srcElement : event.target;
		let index = obj.previousSibling.value
		/*把當前的值賦給原來的title內容*/
		this.state.arr[index].title = event.target.value;
		// this.update(this.state.arr[index]);
		/*重新渲染*/
		this.setState(this.state)
		// console.log(event.target.value)
	}

	/*渲染方法*/
	render(){
		/*儲存陣列用map迴圈遍歷之後的值*/
		var todos = null;
		/*把arr遍歷*/
		todos = this.state.arr.map(
			(item,index)=>{
				/*model是儲存返回span和input的變數*/
				let model;
				/*如果他的值為true就返回span,否則返回input*/
				if(item.bol){
					/*這裡span引用了三元表示式,根據completed屬性來判斷給文字加上什麼樣式*/
					model = <span onClick={this.onInput.bind(this)} className={(item.completed)?"change":"sapn1"}>{item.title}</span>
				}else{ 
					model = <input onBlur={this.onInput.bind(this)} onChange={this.onInputChange.bind(this)} type="text" value={item.title}/>
				}

				/*返回渲染後的樣式加資料*/
				return <li key={item.id}>
				<input  type="checkbox" checked={item.completed?"checked":null} value={index} onChange={this.onCheck.bind(this)}/>
				{model}
				</li>
			}
		)
		/*這個才是渲染的方法*/
		return(
			<div>
			<ul id="ul1" className="todolist_li">
				{todos}
			</ul>
			<p>完成了{this.state.wancheng}個任務,還有{this.state.weiwan}個未完成<span onClick={this.deleteVal.bind(this)}>【完成】</span></p>
			</div>
			)
		todos="";
	}
}

module.exports = todolist;

NODE.JS

var http = require("http");
var url = require("url");
var mysql      = require('mysql');
var querystring = require('querystring');




var http = require("http");
var url = require("url");
var mysql      = require('mysql');
var querystring = require('querystring');
const express = require('express')
const Router = express.Router()


var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : '1234',
  database : 'goods'
});
connection.connect();

var find = () => new Promise(resolve=>{
  connection.query('SELECT * from todolist', function (error, results, fields) {
    if (error) throw error;
    resolve(results);
  });
})
//delete是關鍵字
var delete1 = (id) => new Promise(resolve=>{
  connection.query('delete from TodoList where id = ?',[id], function (error, results, fields) {
    if (error) throw error;
    resolve(results);
  });
})
var add1 = (title) => new Promise(resolve=>{
  connection.query('INSERT INTO TodoList(title) VALUES(?)',[title], function (error, results, fields) {
    if (error) throw error;
    resolve(results);
  });
})
var update1 = (title,completed,bol,id) => new Promise(resolve=>{
  connection.query('update TodoList set title=?,completed=?,bol=? where id=?',[title,completed,bol,id], function (error, results, fields) {
    if (error) throw error;
    resolve(results);
  });
})


var httpServer = http.createServer(
  function(req,res){
    if (req.url=="/favicon.ico") {return;}//假如訪問的路徑是網站圖片

    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf8','Access-Control-Allow-Origin':"*"});
    let urlString = req.url;
    let url1 = url.parse(urlString,true);
    console.log(url1);
    let loginName = url1.pathname;
    // res.end(loginName);

    if (loginName=='/find') {
      find().then(
        value=>{
          res.end(JSON.stringify(value));
        })
    }//find
    else if(loginName=='/delete'){
      // console.log("delete")
      // console.log(url1.query.id);
      let id = url1.query.id;
      delete1(id).then(
        value=>{
          res.end(value+"");
        })
    }//delete
    else if(loginName=='/add'){
      let title = url1.query.title;
      add1(title).then(
        value=>{
          res.end(value+"");
        })
    }//add
    else if(loginName=='/update'){
      let title = url1.query.title;
      let completed = url1.query.completed;
      let bol = url1.query.bol;
      let id = url1.query.id;
      if (completed==0) {
        completed=false;
      }else{
        completed=true;
      }
      if (bol==0) {
        bol=false;
      }else{
        bol=true;
      }
      console.log(title+completed+bol+id)
      update1(title,completed,bol,id).then(
        value=>{
          res.end(value+"");
        })
    }

    
    let userName = url1.query.userName;
    let pass = url1.query.pass;
    
  });

httpServer.listen(8080,"192.168.1.104");



// 解析後的路徑物件
// Url {
//   protocol: null,
//   slashes: null,
//   auth: null,
//   host: null,
//   port: null,
//   hostname: null,
//   hash: null,
//   search: '?userName=jin&pass=123',
//   query: { userName: 'jin', pass: '123' },
//   pathname: '/login',
//   path: '/login?userName=jin&pass=123',
//   href: '/login?userName=jin&pass=123' }
// { Url: [Function: Url],
//   parse: [Function: urlParse],
//   resolve: [Function: urlResolve],
//   resolveObject: [Function: urlResolveObject],
//   format: [Function: urlFormat],
//   URL: [Function: URL],
//   URLSearchParams: [Function: URLSearchParams],
//   domainToASCII: [Function: domainToASCII],
//   domainToUnicode: [Function: domainToUnicode] }