项目实战【vue,react,微信小程序】(1705E)

目录

 

 

 

 

一、git

1、git简介

2、github简介

3、在github上创建项目

4、克隆代码

5、提交代码

6、git工作区

7、分支

8、对比分支

9、生成ssh key

10、安装git

11、安装小乌龟

12、忽略提交.gitignore

13、git配置用户名和邮箱

14、git免密

参考链接

二、MySql

1、安装mysql

2、安装Navicat

3、破解Navicat

4、Navicat连接mysql报错的解决办法

5、使mysql允许外部连接访问

6、Navicat建立MySql连接

7、sql语句简介

8、nodejs封装sql查询

9、不使用vue.config.js,单独使用node

10、封装api接口

11、axios拦截器

12、redis

13、jwt-simple

14、uuid

15、node操纵mysql数据库进行增删查改以及登录退出

三、vue

1、周考一

四、react

1、hook入门

五、微信小程序

1、书城

 

github源码


 

 

 

 

一、git

1、git简介

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。

Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。

2、github简介

章鱼猫:GitHub的吉祥物(Octocat)

GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名GitHub。

2018年6月4日,微软宣布,通过75亿美元的股票交易收购代码托管平台GitHub。

3、在github上创建项目

4、克隆代码

git clone git@github.com:baweireact/m-app-test.git

5、提交代码

添加要上传的文件:

git add README.md

提交到本地:

git commit -m "first commit"

提交到远程:

git push origin master

  

git add readme.txt

git add readme.txt ant.txt

git add *.html

git add all 

git add .

git add *

git log

git status

git add . 会把本地所有untrack的文件都加入暂存区,并且会根据.gitignore做过滤,但是git add * 会忽略.gitignore把任何文件都加入 

6、git工作区

使用 git add 命令将想要快照的内容写入缓存区, 而执行 git commit 将缓存区内容添加到本地仓库中。 

7、分支

::切换到develop分支
git checkout beta

git pull origin beta

::把develop分支的代码合并到beta上
git merge develop

git status

::push到远程beta
git push origin beta

::切换到develop分支 
git checkout develop

echo. & pause 

新建分支:

git branch feature_x

将分支提交到远程:

git push origin feature_x

切换分支:

git checkout master

查看有所有分支:

git branch -a

查看本地分支:

git branch

创建新分支并立即切换到该分支下:

git checkout -b feature_login

在github上查看有哪些分支:

删除本地分支:

git branch -d feature_x

删除远程分支:

git push origin -d feature_x

合并分支,合并后再提交到远程仓库(先切换到master分支,然后合并feature_login分支到master分支,然后再把合并后的代码提交到远程仓库):

git merge feature_login

git push origin master

查看历史记录(按Q键退出历史记录):

git log

查看简洁历史记录:

git log --oneline

反顺序的历史记录:

git log --reverse

8、对比分支

git diff master feature_login

9、生成ssh key

  git clone 时,可以所用不同的协议,包括 ssh, git, https 等,其中最常用的是 ssh,因为速度较快,还可以配置公钥免输入密码

ssh-keygen -t rsa -C "1183391880@qq.com"

生成的key的位置:

github添加key:

点击setting:

新建ssh key :

把生成的key粘贴到github上:

 确保启用 SSH 代理:

$ eval "$(ssh-agent -s)"

为 SSH key 启用 SSH 代理:

$ ssh-add ~/.ssh/id_rsa

10、安装git

11、安装小乌龟

配置ssh:

12、忽略提交.gitignore

在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。

/mtk 过滤整个文件夹
*.zip 过滤所有.zip文件

参考链接:

https://www.jianshu.com/p/74bd0ceb6182

13、git配置用户名和邮箱

   全局配置用户名:

git config --global user.name "xutongbao"

   全局配置邮箱:

git config --global user.email "1183391880@qq.com"

14、git免密

ssh配置失败的同学,可以用https协议下载代码,而且也可以配置免密!

用git时,每次都需要输入密码会比较麻烦。
可以进行设置,这样在输入过一次密码之后,以后就不需要每次都输入密码了。
打开终端输入 :

touch ~/.git-credentials

再输入:

git config --global credential.helper store

参考链接

git使用简易指南:

https://www.bootcss.com/p/git-guide/

加入到暂存区参考链接:

http://www.softwhy.com/article-8489-1.html

设置ssh key出问题的可以参考下面的链接:

https://blog.csdn.net/felicity294250051/article/details/53606158

https://blog.csdn.net/goawaycow1/article/details/78069487

二、MySql

1、安装mysql

2、安装Navicat

3、破解Navicat

4、Navicat连接mysql报错的解决办法

第一句:修改加密规则

第二句:更新用户密码

第三句:刷新权限

alter user 'root'@'localhost' identified by 'root' password expire never;

alter user 'root'@'localhost' identified with mysql_native_password by 'root';

flush privileges;

参考链接:

https://www.jianshu.com/p/c8eb6d2471f8

5、使mysql允许外部连接访问

update user set host='%' where user='root';

flush privileges;

6、Navicat建立MySql连接

7、sql语句简介

 通过sql语句实现增删查改:

-- 建表
create table user (
	id varchar(100) primary key,
	username varchar(100),
	password varchar(100)
);

-- 增
insert into user values ('001', 'admin', '123456');
insert into user values ('002', 'xu', '123456');
insert into user values ('003', 'xutongbao', '123456');

-- 删
delete from user;

delete from user where id = '003';

-- 查
select * from user;

select username from user;

select * from user where id = '002';

-- 模糊搜索
select * from user where username like '%n%';

-- 降序
select * from user order by username desc;

-- 升序
select * from user order by username asc;

-- 分页
select * from user order by username asc limit 1,2;

-- 数量
select count(*) from user;


-- 改
update user set password = '123';

update user set password = '1234' where id = '001';

8、nodejs封装sql查询

mysqlQuery.js:

const mysql = require('mysql')

let connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'demo'
})

connection.connect((error) => {
  if (error) {
    console.log('失败')
  } else {
    console.log('成功')
  }
})

//使用回调函数返回查询结果
const query = (sql, callback) => {
  connection.query(sql, (error, results) => {
    if (error) {
      throw error
    } else {
      callback && callback(results)
    }
  })
}

//使用promise封装sql查询
const queryPromise = (sql) => {
  return new Promise((resolve, reject) => {
    connection.query(sql, (error, results) => {
      if (error) {
        reject(error)
      } else {
        resolve(results)
      }
    })
  })
}

module.exports = {
  query,
  queryPromise
}

vue.config.js:

const { query, queryPromise } = require('./mysqlQuery')

module.exports = {
  devServer: {
    open: true,
    before(app) {
      app.get('/api/get_user_query', async (req, res) => {
        query(`select * from user`, (results) => {
          res.send({
            code: 200,
            data: results,
            message: '用户列表'
          })
        })
      })
      app.get('/api/get_user', async (req, res) => {
        let results = await queryPromise(`select * from user`)
        res.send({
          code: 200,
          data: results,
          message: '用户列表'
        })
      })
    }
  }
}

9、不使用vue.config.js,单独使用node

主要是为了可以使用nodemon,后端代码改变时不需要重启

const express = require('express')
const cors = require('cors')
const { queryPromise } = require('./mysqlQuery')

const app = express()

app.use(cors())

app.get('/api/get_user', async (req, res) => {
  let users = await queryPromise('select * from user')
  res.send({
    code: 200,
    data: users,
    message: '用户列表'
  })
})

app.listen(3000, () => {
  console.log('3000端口')
})

参考链接:

跨域:

http://www.expressjs.com.cn/en/resources/middleware/cors.html

express:

http://www.expressjs.com.cn/starter/hello-world.html

nodemon:

https://www.npmjs.com/package/nodemon

10、封装api接口

index.js:

import axios from 'axios'
import url from './url'

axios.defaults.baseURL = 'http://localhost:3000'

const common = async (config) => {
  const response = await axios(config)
  return response
}

export default {
  getUser: () => common({ url: url.getUser })
}

url.js:

export default {
  getUser: '/api/get_user'
}

11、axios拦截器

前端请求前添加token,请求后判断状态码:

import axios from 'axios'
import url from './url'

axios.defaults.baseURL = 'http://localhost:3000'

axios.interceptors.request.use((config) => {
  config.headers.token = '666'
  return config
})

axios.interceptors.response.use((res) => {
  if (res.data.code === 200) {
    return res
  } else if (res.data.code === 400) {
    alert(res.data.message)
    return res
  } else if (res.data.code === 403) {
    window.location.href = '/login'
  }
})

const common = async (config) => {
  const response = await axios(config)
  return response
}

export default {
  getUser: () => common({ url: url.getUser })
}

后端接收token:

const express = require('express')
const cors = require('cors')
const { queryPromise } = require('./mysqlQuery')

const app = express()

app.use(cors())

app.get('/api/get_user', async (req, res) => {
  let token = req.headers.token
  console.log(token)
  let users = await queryPromise('select * from user')
  res.send({
    code: 400,
    data: users,
    message: '用户列表'
  })
})

app.listen(3000, () => {
  console.log('3000端口')
})

参考链接:

http://www.axios-js.com/docs/#Interceptors

12、redis

用于保存token

安装:

启动:

在控制台使用:

//启动
redis-server.exe redis.windows.conf

//访问
redis-cli.exe -h 127.0.0.1 -p 6379

//设置值
set a 1

//获取值
get a

//删除key
del a

//设置一个值20秒后删除
set a 1 EX 20

参考链接:

https://www.npmjs.com/package/redis

13、jwt-simple

用于生成token

参考链接:

https://www.npmjs.com/package/jwt-simple

14、uuid

用于生成用户id

参考链接:

https://www.npmjs.com/package/uuid

15、node操纵mysql数据库进行增删查改以及登录退出

app.js:

const express = require('express')
const cors = require('cors')
const redis = require('redis')
const bodyParser = require('body-parser')
const jwt = require('jwt-simple')
const uuidv1 = require('uuid/v1')
const { queryPromise } = require('./mysqlQuery')

const app = express()

//跨域
app.use(cors())
app.use(bodyParser.json())

var secret = 'xxx';

//如果没有启动redis,会报错,启动redis方法,在cd到redis的安装目录,执行redis-server.exe redis.windows.conf
const client = redis.createClient()
client.on('error', (err) => {
  console.log('redis错误:' + err)
})

//检查token是否存在,并更新token过期时间
const checkToken = async (token) => {
  let result = await new Promise((resolve) => {
    client.get(token, function (err, res) {
      return resolve(res);
    });
  });
  console.log(result)
  if (result) {
    client.set(token, token , 'EX', 600)
    return true
  } else {
    return false
  }
}

//增
app.post('/api/add_user', async (req, res) => {
  let token = req.headers.token
  let { username, password } = req.body
  let isLogin = await checkToken(token)
  if (isLogin) {
    let users = await queryPromise(`select * from user where username = '${username}'`)
    console.log(users)
    if (users.length > 0) {
      res.send({
        code: 400,
        data: {
          username
        },
        message: '用户名已存在'
      })
    } else {
      let id = uuidv1()
      let user = await queryPromise(`insert into user values('${id}', '${username}', '${password}')`)
      if (user) {
        res.send({
          code: 200,
          data: user,
          message: '添加成功'
        })
      }
    }
  } else {
    res.send({
      code: 403,
      message: '登录过期'
    })
  }
})

//删
app.post('/api/delete_user', async (req, res) => {
  let token = req.headers.token
  let { ids } = req.body
  let isLogin = await checkToken(token)
  if (isLogin) {
    let idString = ''
    for (let i = 0; i < ids.length; i++) {
      if (i === ids.length - 1) {
        idString += ` id = '${ids[i]}' `
      } else {
        idString += ` id = '${ids[i]}' or `
      }
    }
    let result = await queryPromise(`delete from user where ${idString}`)
    res.send({
      code: 200,
      data: result,
      message: '删除成功'
    })
  } else {
    res.send({
      code: 403,
      message: '登录过期'
    })
  }
})

//查
app.get('/api/get_user', async (req, res) => {
  let token = req.headers.token
  let isLogin = await checkToken(token)
  if (isLogin) {
    let users = await queryPromise('select * from user')
    res.send({
      code: 200,
      data: users,
      message: '用户列表'
    })
  } else {
    res.send({
      code: 403,
      message: '登录过期'
    })
  }
})

//改
app.post('/api/update_user', async (req, res) => {
  let token = req.headers.token
  let { id, username, password } = req.body
  let isLogin = await checkToken(token)
  if (isLogin) {
    let result = await queryPromise(`update user set username = '${username}', password = '${password}' where id = '${id}' `)
    res.send({
      code: 200,
      data: result,
      message: '更新成功'
    })
  } else {
    res.send({
      code: 403,
      message: '登录过期'
    })
  }
})

//登录
app.post('/api/login', async (req, res) => {
  let { username, password } = req.body
  let users = await queryPromise('select * from user')
  let user = users.find(item => item.username === username && item.password === password)
  if (user) {
    let token = jwt.encode(user.id, secret)
    client.set(token, token , 'EX', 600)  //60秒后验证码过期知道
    res.send({
      code: 200,
      data: {
        username,
        token
      },
      message: '登录成功'
    })
  } else {
    res.send({
      code: 400,
      message: '登录失败'
    })
  }
})

//退出
app.post('/api/login_out', (req, res) => {
  let token = req.headers.token
  client.del(token)
  res.send({
    code: 200,
    message: '退出'
  })
})

app.listen(3000, () => {
  console.log('3000端口')
})

mysqlQuery.js:

const mysql = require('mysql')

let connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'demo'
})

connection.connect((error) => {
  if (error) {
    console.log('失败')
  } else {
    console.log('成功')
  }
})

//使用回调函数返回查询结果
const query = (sql, callback) => {
  connection.query(sql, (error, results) => {
    if (error) {
      throw error
    } else {
      callback && callback(results)
    }
  })
}

//使用promise封装sql查询
const queryPromise = (sql) => {
  return new Promise((resolve, reject) => {
    connection.query(sql, (error, results) => {
      if (error) {
        reject(error)
      } else {
        resolve(results)
      }
    })
  })
}

module.exports = {
  query,
  queryPromise
}

三、vue

1、周考一

四、react

1、hook入门

React的组件化给前端开发带来了前所未有的体验,我们可以像玩乐高玩具一样将组件堆积拼接起来,组成完整的UI界面,在加快开发速度的同时又提高了代码的可维护性。

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

hook = 钩子

 

参考链接:

https://cloud.tencent.com/developer/article/1468196

https://react.docschina.org/docs/hooks-intro.html

useState、useEffect:

import React, { useState, useEffect } from 'react'

const App = () => {
  const [ count, setCount ] = useState(0)
  const [ obj, setObj ] = useState({
    name: 'xu',
    job: 'web'
  })

  //初始化state可以使用函数
  const [ name, setName ] = useState(() => {
    return 'xu'
  })
  
  //每次更新完都会执行
  useEffect(() => {
    console.log(count)
    return () => {
      console.log('执行当前effect之前对上一个effect进行清除!' + count)
    }
  })

  //只执行一次
  useEffect(() => {
    console.log('只执行一次!')
  }, [])

  useEffect(() => {
    console.log('count更新时执行' + count)
  }, ['count'])

  return (
    <div>
      { count }
      <div>
        <button onClick={() => { setCount(count - 1) }}>减</button>
        <button onClick={() => { setCount(count + 1) }}>加</button>
        <button onClick={() => { setCount(prevCount =>  {
          return prevCount + 1
        }) }}>加</button>
        <button onClick={() => setCount(0)}>重置</button>
      </div>
      { obj.name }, { obj.job }
      <div>
        <button onClick={() => setObj({ name: '徐' })}>改名(删除了job字段)</button>
        <button onClick={() => setObj( prevObj => {
          return {...prevObj,  name: '星河'}
        })}>改名(不会删除job字段)</button>
      </div>
      <div>
        {name}
      </div>
    </div>
  )
}

export default App

useReducer:

import React, { useReducer } from 'react'

const initalState = { count: 0 }

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 }
    case 'decrement':
      return { count: state.count - 1 }
    default:
      return state
  }
}

const App = () => {
  const [state, dispatch] = useReducer(reducer, initalState)
  return (
    <div>
      {state.count}
      <div>
        <button onClick={() => { dispatch({ type: 'decrement' }) }}>减</button>
        <button onClick={() => { dispatch({ type: 'increment' }) }}>加</button>
      </div>
    </div>
  )
}

export default App

使用函数初始化state:

import React, { useReducer } from 'react'

const initalState = { count: 0 }

const init = (a) => {
  return {count: a.count + 1}
}

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 }
    case 'decrement':
      return { count: state.count - 1 }
    default:
      return state
  }
}

const App = () => {
  const [state, dispatch] = useReducer(reducer, initalState, init)
  return (
    <div>
      {state.count}
      <div>
        <button onClick={() => { dispatch({ type: 'decrement' }) }}>减</button>
        <button onClick={() => { dispatch({ type: 'increment' }) }}>加</button>
      </div>
    </div>
  )
}

export default App

useRef,输入框获取焦点:

import React, { useRef, useEffect } from 'react'

const App = () => {
  const inputEl = useRef(null)

  const handleFocus = () => {
    inputEl.current.focus()
  }  

  useEffect(() => {
    inputEl.current.focus()
  }, [])

  return (
    <div>
      <input ref={inputEl}></input>
      <div>
        <button onClick={handleFocus}>获取焦点</button>
      </div>
    </div>
  )
}

export default App

自定义hook,获取上一轮的state:

import React, { useState, useRef, useEffect } from 'react'

//自定义hook,获取上一轮的state
const usePrevious = (value) => {
  const ref = useRef()
  useEffect(() => {
    ref.current = value
  })
  return ref.current
}

const App = () => {
  const [ count, setCount ] = useState(0)

  const prevCount = usePrevious(count)

  return (
    <div>
      {count}, {prevCount}
      <div>
        <button onClick={() => setCount(count + 1)}>加</button>
      </div>
    </div>
  )
}

export default App

获取数据:

function SearchResults() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('react');

  useEffect(() => {
    let ignore = false;

    async function fetchData() {
      const result = await axios('https://hn.algolia.com/api/v1/search?query=' + query);
      if (!ignore) setData(result.data);
    }

    fetchData();
    return () => { ignore = true; }
  }, [query]);

  return (
    <>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ul>
        {data.hits.map(item => (
          <li key={item.objectID}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </>
  );
}

2、路由懒加载,代码分割

参考链接:

https://zh-hans.reactjs.org/docs/react-api.html#reactsuspense

https://blog.csdn.net/xutongbao/article/details/84822315

import React, { Component, Suspense, lazy } from 'react'
import { Switch, Route, NavLink, Redirect } from 'react-router-dom'
// import Home from './Home'
// import MyBook from './MyBook'
import Detail from './Detail'
import Loading from '../components/Loading'
const MyBook = lazy(() => import('./MyBook'))
const Home = lazy(() => import('./Home'))

class Index extends Component {
  render() {
    return (
      <div>
        <div>
          <NavLink to="/index/home" className="m-nav-item">首页</NavLink>
          <NavLink to="/index/my_book" className="m-nav-item">书架</NavLink>
        </div>
        <Suspense fallback={<Loading></Loading>}>
          <Switch>
            <Route exact path="/index/home" component={Home}></Route>
            <Route path="/index/my_book" render={() => {
              if (localStorage.getItem('username')) {
                return <MyBook></MyBook>
              } else {
                return <Redirect to="/login"></Redirect>
              }
            }}></Route>
            <Route path="/index/home/detail/:id" component={Detail}></Route>
          </Switch>
        </Suspense>
      </div>
    )
  }
}

export default Index

3、图片懒加载

装包:

yarn add react-lazy-load
        <LazyLoad height={300} onContentVisible={() => console.log(item.title)}>
          <img src={item.avatar} ></img>
        </LazyLoad>

 参考链接:

https://www.npmjs.com/package/react-lazy-load

五、微信小程序

1、购物车

2、入门

申请账号:

https://mp.weixin.qq.com/wxopen/waregister?action=step1

安装开发者工具:

登录账号:

https://mp.weixin.qq.com/

3、轮播图

参考链接:https://www.cnblogs.com/zjjDaily/p/8041734.html

  <swiper 
    indicator-dots="{{true}}"
    autoplay="{{true}}"
    interval="{{1000}}"
    style="height:{{height}}px">
    <swiper-item wx:for="{{banner}}" wx:key="{{index}}">
      <image src="{{item}}" mode="widthFix" class="m-item-img" bindload="handleImageLoad"></image>
    </swiper-item>
  </swiper>

4、tabbar

  "tabBar": {
    "list": [{
      "text": "首页",
      "selectedIconPath": "./static/index-active.png",
      "iconPath": "./static/index.png",
      "pagePath": "pages/home/index"
    }, {
      "text": "书架",
      "selectedIconPath": "./static/cart-active.png",
      "iconPath": "./static/cart.png",
      "pagePath": "pages/mybook/mybook"
    }]
  }

 5、不支持状态管理

https://developers.weixin.qq.com/community/develop/doc/d4b0566fcd760a529181f2d4b009341c?_at=1558693595388

六、node 

1.koa,egg

$ npm i egg-init -g
$ egg-init egg-example --type=simple
$ cd egg-example
$ npm i

egg官网:https://eggjs.org/zh-cn/intro/quickstart.html

 

github源码

https://github.com/baweireact/m-app-1705E

原文地址:https://www.cnblogs.com/xutongbao/p/11915672.html