项目实战【vue,react,微信小程序】(1705E)
目录
一、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
安装开发者工具:
登录账号:
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、不支持状态管理
六、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
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步