第一个目的:这一个移动端记账本的创作来源呢,其实是我在学习了理财的课程之后,突然想为自己写一个记账的东西来记录自己每天花费的钱,从而可以降低那些不必要的开销,从而达到理财的第一步。
当然还有另一个目的就是:做这个移动端简单的项目,主要是为了熟悉vue.js,从项目构建到完成目录,以及后台数据库的设计,后台逻辑的处理,全程由我自己一个人完成,这个项目历史大概有1个多月吧,虽然项目看起来很小,但是简单亦不简单啊,这个时间段遇到很多问题,都是自己一个人靠着百度,自己理解解决了问题,总的来说,这个项目对我来还是蛮重要的,还是我的第一个开源项目吧,希望大佬不要嘲笑,看到的尽管留言,给出完善的意见,感谢
其用法如下:
holder.js 可以帮我们快速生成占位图片,而且还能定义占位图片的一些基本样式。
用法简单,可以直接去官网下载,或直接引用Bootcss的CDN :
1、基本:默认单位为px,用小写的x连接图片的宽高:
3、让占位图片在缩放长宽比,可以加上auto参数:
4、配色方案:
holder.js共定义了6种占位图片配色,分别是:sky、vine、lava、gray、industrial、social
配色可以通过theme参数设置:
VConsole:移动端调试插件
使用
废话不多说,说说怎么使用的吧。
首先去下载相关的代码,由于只需要在页面引入一个js文件,直接去下载就可以,https://github.com/Tencent/vConsole/releases/tag/v3.1.0
或者使用 npm 安装:
npm install vconsole
使用webpack,然后js代码中
import VConsole from 'vconsole/dist/vconsole.min.js' //import vconsole
let vConsole = new VConsole() // 初始化
或者找到这个模块下面的 dist/vconsole.min.js ,然后复制到自己的项目中
axios:地址入口 : https://www.kancloud.cn/yunye/axios/234845
用法如下:
安装
使用 npm:
$ npm install axios
使用 bower:
$ bower install axios
使用 cdn:
Example
执行 GET 请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
axios API
可以通过向 axios 传递相关配置来创建请求
axios(config)
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
axios(url[, config])
// 发送 GET 请求(默认的方法)
axios('/user/12345');
请求方法的别名
为方便起见,为所有支持的请求方法提供了别名
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
rem.js
// 设置字体大小
setFontSize(){
(function(doc,win){
var docEl = doc.documentElement, //文档根标签
resizeEvent = 'orientationchange' in window ? 'orientationchang' :'resize'; //viewport变化事件源
var rescale = function(){
//重置方法
win.clientWidth = docEl.clientWidth;
if (!win.clientWidth) return;
// 改变DOM根节点fontSize大小的值;
// (屏幕宽度/设计图宽度) = 缩放或扩大的比例值;
docEl.style.fontSize = 40 * (win.clientWidth / 750) + 'px';
}
if (!doc.addEventListener) return;
win.addEventListener(resizeEvent, rescale, false);
doc.addEventListener('DOMContentLoaded', rescale, false);
})(document, window);
}
axios_get_post.js
// eslint-disable-next-line
/* eslint-disable */
// 对 axios.get() 和 axios.post()进行封装
import axios from 'axios'
import qs from 'qs'
/*
post 方式
axios({
method: 'post',
url: '/user/123456',
data: {
username: 'ken',
password: '123456'
}
})
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
get 方式
axios({
method: 'get',
url: '/user/123456',
})
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
//伪代码的编写
axios({
method: 'post' || 'get',
url: '/user/123456',
data: {
username: 'ken',
password: '123456',
} || params: {
ID: '123456'
}
})
*/
export default function axios_get_post(params){
return new Promise((resolve, reject)=>{
let opt = {
method: params.method || 'get',
url: params.url,
headers: {
'Content-Type':'application/x-www-form-urlencoded'
},
}
if(params.method == 'post'){
opt.data = params.data
}else {
//
opt.params = params
}
// 拦截处理
axios.interceptors.request.use((req) => {
if (req.method === 'post') {
// 转换成JSON格式
req.data = qs.stringify(req.data);
}
return req;
}, (error) => Promise.reject(error));
axios(opt).then(res=>{
resolve(res.data)
}).catch(err=>{
reject(err)
})
})
}
axios.js以post方式传递数据后台获取不到数据,这到底是什么原因
在这个项目中使用的最多就是MessageBox()这个组件
npm 安装
推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
npm i mint-ui@1 -S
CDN
目前可以通过 unpkg.com/mint-ui@1 获取到最新版本的资源,在页面上引入 js 和 css 文件即可开始使用。
Hello world
通过 CDN 的方式我们可以很容易地使用 Mint UI 写出一个 Hello world 页面。
按钮
引入
import { MessageBox } from 'mint-ui';
例子
以标题与内容字符串为参数进行调用
MessageBox('提示', '操作成功');
或者传入一个对象
MessageBox({
title: '提示',
message: '确定执行此操作?',
showCancelButton: true
});
此外,MessageBox 还提供了 alert、confirm 和 prompt 三个方法,它们都返回一个 Promise
MessageBox.alert(message, title);
MessageBox.alert('操作成功').then(action => {
...
});
MessageBox.confirm(message, title);
MessageBox.confirm('确定执行此操作?').then(action => {
...
});
MessageBox.prompt(message, title);
MessageBox.prompt('请输入姓名').then(({ value, action }) => {
...
});
Infinite scroll
引入
import { InfiniteScroll } from 'mint-ui';
Vue.use(InfiniteScroll);
例子
为 HTML 元素添加 v-infinite-scroll 指令即可使用无限滚动。滚动该元素,当其底部与被滚动元素底部的距离小于给定的阈值(通过 infinite-scroll-distance 设置)时,绑定到 v-infinite-scroll 指令的方法就会被触发。
- {{ item }}
loadMore() {
this.loading = true;
setTimeout(() => {
let last = this.list[this.list.length - 1];
for (let i = 1; i <= 10; i++) {
this.list.push(last + i);
}
this.loading = false;
}, 2500);
}
之前有些过一篇关于这个组件的博客文章:https://blog.csdn.net/qq_36772866/article/details/86530684
也在知乎写过同样的文章:
https://zhuanlan.zhihu.com/p/55123532
码云地址如下:https://gitee.com/kennana/vue_component.git
只需要:git clone https://gitee.com/kennana/vue_component.git
cd vue_component //进入vue_component目录
npm install //执行此命令
npm run serve //执行此命令即可将项目跑起来
vue.js请求后台遇到跨域引爆这篇文章
vue-cli3的本地代理配置
一. vue lazyload插件:
插件地址:https://github.com/hilongjw/vue-lazyload
demo:http://hilongjw.github.io/vue-lazyload/
二. 简单使用实例:
这个插件还是蛮好用的,就是感觉这个插件的开发文档有点太啰嗦了,一股脑把所有的api扩展都罗列出来,源码中并没有可以运行的实例提供。
其实这个插件做简单使用的话是很简单的,看官方文档的话反而被误导了,可以先按下边的实例实现简单引用,后边再根据开发文档做扩展。
npm install vue-lazyload --save-dev
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad,{
error:'./static/error.png',
loading:'./static/loading.png'
})
// 在进入下一个路由的时候,就获取到下一个页面的title显示出来
// 需要注册一个全局守卫
router.beforeEach((to, from, next)=>{
if(to.path=='/'){
//如果即将进入登录页面就是直接放心进入
next()
}else{
if(to.meta.requiresAuth && !localStorage.getItem('token')){
// 验证token是否存在
// to.meta.requiresAuth 是否为真
next({
path: '/',
})
}else{
if(to.meta.title){
document.title = to.meta.title
}
next();
}
}
})
router.js
// eslint-disable-next-line
/* eslint-disable */
import Vue from 'vue'
import Router from 'vue-router'
// import Login from "./views/Login.vue"
Vue.use(Router)
export default new Router({
routes:[
{
name: 'login',
path: '/',
component: ()=>import("./views/Login.vue"),
meta: {
title: '登录'
},
},
{
name: 'register',
path: '/register',
component: ()=>import("./views/Register.vue"),
meta: {
title: "注册"
}
},
{
name: 'addinfo',
path: '/addinfo',
component: ()=>import("./views/AddInfo.vue"),
meta: {
title: '记账',
requiresAuth: true,
}
},
{
name: 'editinfo',
path: '/editinfo/:id',
component: ()=>import("./views/EditInfo.vue"),
meta: {
title: '编辑',
requiresAuth: true,
}
},
{
name: 'showinfo',
path: '/showinfo',
component: ()=>import("./views/ShowInfo.vue"),
meta: {
title: '显示信息',
requiresAuth: true,
}
},
{
name: 'editriqi',
path: '/editriji',
component: ()=>import("./views/EditRiQi.vue"),
meta: {
title: '写日记',
requiresAuth: true
}
},
{
name: 'info',
path: '/info/:id',
component: ()=>import("./views/Info.vue"),
meta: {
title: '详细信息',
requiresAuth: true
}
}
]
})
最近在调试代码时发现有Request Payload的情况,从网上查一些文件,
也都有较多的描述。下面我只是说明一下大家没有注意的地方
关于HTTP请求,都是通过URL及参数向后台发送数据。
主要方式有GET, POST。对这两种方式,GET的参数都会放在URL的后面,
一般称之为query参数。
POST的都放在HTTP的报文BODY里,可以query参数的形式,
也可以multipart格式,还有一种JSON格式,即Request Payload格式。
multipart, Request Payload是通过request Header中的ContentType区分的:
multipart格式:ContentType: multipart/form-data;boundary=--xxxxxxx,
注意对multipart的格式都要有boundary做为BODY中的参数分隔符,
(关于该格式的讲解以后再写)
Request Payload格式:ContentType: application/json
在后台的处理中对这三种格式的处理是不相同的。
GET格式都在URL后面,以key1=value1&key2=value2的KV格式存在,
且不会很长(协议规定为1024个字节,但现在浏览器都会适当加长一些)。
后台处理这种参数时可以使用同步处理,因为报文头收到后参数也就收全了。
POST时参数也可以使用上面的KV格式存在,但是会放在报文体中。
当数据量不大时,一般也会和报文头一起收到。
但数据量大的时会被拆分到多个报文中。因此必须使用异步方式收取。收全后处理同GET相同。
对于multipart格式,需要使用流方式边收边解析,因为有可能是大文件上传。
对于RequestPayload格式,可能也是异步发送(这个没有验证过),
但数据量一般不会太大,因此它是一个JSON格式,因此必须等报文收全后才能处理。
目前对JSON格式的支持比较普遍,都有相关的函数来解析JSON字符串,
直接生成JSON对象,因此这种方式也是最方便的。
特别是使用nodejs server时就可以直接在代码中使用了。
import qs from "qs"
axios.interceptors.request.use((req) => {
if (req.method === 'post') {
// 转换成JSON格式
req.data = qs.stringify(req.data);
}
return req;
}, (error) => Promise.reject(error));
https://www.cnblogs.com/xuzhudong/p/8487119.html
https://blog.csdn.net/zwq912318834/article/details/79930423
第一种方式:Form Data
return request({
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
transformRequest: [function(data) { //在请求之前对data传参进行格式转换
data = Qs.stringify(data)
return data
}],
url: '/test/add', //接口地址
method: 'post', //请求类型
params: {},
data: {
'name': params.name, //传的参数
'jobId': params.jobId,
'department': params.department,
'phone': params.phone,
'position ': params.position,
'permis': params.permis,
'entryTime': params.entryTime
}
})
第二种方式:Json字符串
return request({
headers: {
'Content-Type': 'application/json'
},
transformRequest: [function(data) {
data = JSON.stringify(data)
return data
}],
url: '/test/add',
method: 'post',
params: {},
data: {
'name': params.name, //传的参数
'jobId': params.jobId,
'department': params.department,
'phone': params.phone,
'position ': params.position,
'permis': params.permis,
'entryTime': params.entryTime
}
})
原因是 Content-Type类型设置为payload了
在Web开发中,当用户使用浏览器向服务器POST提交数据时,
我们使用php接受用户POST到服务器的数据,并对数据进行解析和相应的处理.
以下是php接受POST数据的几种方式:
一.$_POST 方式接受数据
$_POST 方式是由通过HTTP的POST方法传递过来的数据组成的数组,
是一个自动全局变量.
注:只能接收Content-Type:application/x-www-form-urlencode提交的数据.
也就是只能接收表单POST过来的数据.
二.GLOBLES[‘HTTP_RAW_POST_DATA’]
如果访问原始POST数据不是php能够识别的文档类型,
比如:text/xml 或者soap等等,我们可以用$GLOBLES[‘HTTP_RAW_POST_DATA’]来接收,
$HTTP_RAW_POST_DATA变量包含有原始POST数据.此变量仅在碰到未识别的MIME数据时产生.
注: $HTTP_RAW_POST_DATA对于enctype=”multipart/form-data”表单数据不可用,
也就是说使用$HTTP_RAW_POST_DATA无法接受网页表单post过来的数据.
三. file_get_content(“php://input”);
如果访问原始POST数据, 更好的方法是使用file_get_content(“php://input”);
对于未指定Content-Type的POST数据,可以使用该方法读取POST原始数据,
包括二进制流也可以.和$HTTP_RAW_POST_DATA比起来.
它带来的生存眼里更小,并且不需要任何特殊的php.ini设置.
注: php://input不能用于 enctype=”multipart/form-data”.
例如:
$postStr = file_get_contents("php://input"); //获取POST数据
四.名词解释
1.MIME数据类型:多用途互联网邮件扩展(MIME, Multipurpose Internet Mail Extension)是一个互联网标准,它扩展了电子邮箱标准, 使其能够支持ASCII字符,
二进制格式附件等多种格式的邮件消息.MIME规定了用于表示各种各样的数据类型的符号化方法.此外,在万维网中使用的HTTP协议中也使用MIME的框架.
2.原始数据:原始数据是指尚未处理的数据, 这些数据需要经过萃取,组织甚至分析与格式化后才能呈现给他人看.
//定义编码
header( 'Content-Type:text/html;charset=utf-8 ');
//Atom
header('Content-type: application/atom+xml');
//CSS
header('Content-type: text/css');
//Javascript
header('Content-type: text/javascript');
//JPEG Image
header('Content-type: image/jpeg');
//JSON
header('Content-type: application/json');
//PDF
header('Content-type: application/pdf');
//RSS
header('Content-Type: application/rss+xml; charset=ISO-8859-1');
//Text (Plain)
header('Content-type: text/plain');
//XML
header('Content-type: text/xml');
// ok
header('HTTP/1.1 200 OK');
//设置一个404头:
header('HTTP/1.1 404 Not Found');
//设置地址被永久的重定向
header('HTTP/1.1 301 Moved Permanently');
//转到一个新地址
header('Location: http://www.example.org/');
//文件延迟转向:
header('Refresh: 10; url=http://www.example.org/');
print 'You will be redirected in 10 seconds';
//当然,也可以使用html语法实现
//
$filename = rtrim($_SERVER['DOCUMENT_ROOT'],'/').'/app/files/payment_status.csv';
header('Content-Disposition: attachment; filename=payment_status.xlsx');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Length: ' . filesize($filename));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile($filename);
https://zhuanlan.zhihu.com/p/53981022
https://zhuanlan.zhihu.com/p/54716875
https://zhuanlan.zhihu.com/p/54818773
https://zhuanlan.zhihu.com/p/54867843
https://zhuanlan.zhihu.com/p/55029525
https://zhuanlan.zhihu.com/p/55169371
https://blog.csdn.net/panxiaomao11/article/details/71663032
https://zhuanlan.zhihu.com/p/55226412
https://zhuanlan.zhihu.com/p/55256359
https://zhuanlan.zhihu.com/p/55265206
https://zhuanlan.zhihu.com/p/55279412
登录界面Login.vue
每个页面都要认证,如果说他是没有登录,无论访问哪个页面都跳转到首页登录
request 请求
{
user_name: String 用户名,
user_pass: String 密码
}
response 响应
点击请求登录前台记录本地缓存用户名
缓存用户id
缓存token验证
缓存用户头像img
缓存
{
code: int 0表示成功,其他表示失败,
user_id: int 用户 id,
user_name: string 用户昵称,
user_img: string 用户头像,
message: "登录成功",
token: string,
}
如果用户没有注册过就去登录,要提醒用户去注册
注册页面Register.vue
request 请求
{
user_name: String 用户名,
user_pass: String 密码
}
将用户名写入本地缓存中。
response 响应
{
user_id: int 用户id,
user_name: string 用户昵称,
code: int 0表示成功,其他表示失败,
}
将token写入缓存中
注册成功之后,跳转到登录页面
记账页面AddInfo.vue
request 请求
{
date: string 日期,
morning: string 早餐花费,
afternoon: string 午餐花费,
evening: string 晚餐花费,
other: string 其他花费,
token: string token验证,
userid: int 用户id
}
response 响应
{
code: int 0表示成功,其他表示失败,
message: string 用户提示语,
user_id: int 用户id,
id: int 数据插入的id
}
修改记账EditInfo.vue
request 初始化请求
{
userid: int 用户id,
editid: int 编辑id,
token: string 验证,
}
reponse 初始化,返回特定的一条数据
{
userid: int 用户id,
editid: int 编辑id,
code: int 0表示成功,其他表示失败,
date: string 日期,
morning: string 早餐花费,
afternoon: string 午餐花费,
evening: string 晚餐花费,
other: string 其他花费,
msg: "提示语"
}
修改后request请求
{
date: string 日期,
morning: string 早餐花费,
afternoon: string 午餐花费,
evening: string 晚餐花费,
other: string 其他花费,
userid: int 用户id,
editid: int 编辑id,
token: string 验证,
}
修改后reponse响应
{
userid: int 用户id,
editid: int 编辑id,
code: int 0表示成功,其他表示失败,
msg:"提示语",
}
展示记账简略信息ShowInfo.vue
request 初始化请求
{
userid: int 用户id,
page: int 页数,
count: int 一页显示的数量,
token: string 验证,
}
reponse 初始化,返回特定的一条数据
{
userid: int 用户id,
code: int 0表示成功,其他表示失败,
data: [
{
id: int ,
date: string 日期,
path: string头像
},
{
id: int ,
date: string 日期,
path: string头像
},
{
id: int ,
date: string 日期,
path: string头像
}
],
msg: "提示语"
}
修改后request请求
{
date: string 日期,
userid: int 用户id,
editid: int 编辑id,
token: string 验证,
}
修改后reponse响应
{
userid: int 用户id,
editid: int 编辑id,
code: int 0表示成功,其他表示失败,
msg:"提示语",
}
显示详细信息Info.vue
request 请求
{
userid: int 用户id,
infoid: int 信息id,
token: string 验证,
}
response 响应
{
userid: int 用户id,
editid: int 编辑id,
code: int 0表示成功,其他表示失败,
date: string 日期,
morning: string 早餐花费,
afternoon: string 午餐花费,
evening: string 晚餐花费,
other: string 其他花费,
msg: "提示语"
}
写日记EditRiQi.vue
request 请求
{
userid: int 用户id,
content: string 日记内容,
token: string 验证
}
reponse 响应
{
userid: int 用户id,
code: int 0表示成功,其他表示失败,
msg: "提示语"
}
我的码云地址:https://gitee.com/kennana/mintui_learning
https://blog.csdn.net/qq_36772866/article/details/86530684
https://gitee.com/kennana/mobile_account_book
git clone https://gitee.com/kennana/mobile_account_book.git
cd mobile_account_book
npm install
npm run serve
https://gitee.com/kennana/accounting_backstage
git clone https://gitee.com/kennana/accounting_backstage.git
https://gitee.com/kennana/work_summary
https://gitee.com/kennana/work_summary.git