cnpm i jsonwebtoken -S 安装 token 模块css
var jwt = require('jsonwebtoken'); // 实现登录功能 router.post('/login', (req, res, next) => { // 一、获取表单信息 let { tel, password } = req.body; // 二、依据手机号查询有没有该用户 sql.find(User, { tel }, { _id: 0 }).then(data => { // 2.1 判断有么有该用户 if (data.length === 0) { // 2.2 没有该用户 res.send(utils.unregister) } else { // 2.3 有该用户,验证密码 // 2.3.1 获取数据库中的密码 let pwd = data[0].password; // 2.3.2 比较 输入的 密码和数据库中的密码 var flag = bcrypt.compareSync(password, pwd) // 前为输入,后为数据库 if (flag) { // 2.3.3 密码正确,生成token let userid = data[0].userid let token = jwt.sign({ userid }, 'daxunxun', { // expiresIn: 60*60*24// 受权时效24小时 expiresIn: 60*0.1// 受权时效6s }) res.send({ code: '10010', message: '登录成功', token: token }) } else { // 2.3.4 密码错误 res.send({ code: '10100', message: '密码错误' }) } } }) })
var jwt = require('jsonwebtoken'); app.use((req, res, next) => { // 一、若是不是登录和注册页面 if (req.url !== '/users/login' && req.url !== '/users/register') { // 1.1 获取前端提交的token信息(get/post/头信息) let token = req.headers.token || req.query.token || req.body.token; if (token) { // 1.2 若是存在token,校验token jwt.verify(token, 'daxunxun', function(err, decoded) { if (err) { // 1.2.1 若是校验token失败,返回字段 res.send({ code: '10119', message: '没有找到token.' }); } else { // 1.2.2 若是校验token成功,继续操做接口 req.decoded = decoded; console.log('验证成功', decoded); next() } }) } else { // 1.3 若是没有传递token,返回字段 res.send({ code: '10119', message: '没有找到token.' }); } } else { // 二、若是是登录和注册,继续操做 next() } })
<template> <div class="box"> <header class="header">登录</header> <div class="content"> <input type="text" placeholder="手机号码" v-model="tel"> <p class="tip">{{ teltip }}</p> <input type="password" placeholder="密码" v-model="password"> <p class="tip">{{ passwordtip }}</p> <button class="userBtn" @click="login">登录</button> </div> </div> </template> <script> export default { data () { return { tel: '18813007814', password: '123456' } }, computed: { teltip () { return '手机号码格式错误' }, passwordtip () { return '密码格式错误' } }, methods: { login () { } } } </script> <style lang="scss"> input { outline: none; border: 0; width: 96%; margin: 5px 2%; border-bottom: 1px solid #efefef; text-indent: 10px; display: block; line-height: 36px; } .tip { text-align: center; color: #f66; height: 20px; } .userBtn { outline: none; border: 0; display: block; background-color:#f66; width: 96%; margin: 15px 2%; line-height: 40px; font-size: 18px; color: #fff; } </style>
{ path: '/login', name: 'login', components: { // 一个路由 对象两个位置发生变化 default: () => import('@/views/login/index.vue') } }
浏览器输入 /login 查看效果html
computed: { teltip () { if (this.tel === '') { return '' } else if (this.tel.length !== 11) { return '手机号码格式错误' } else { return '' } }, passwordtip () { if (this.password === '') { return '' } else if (this.password.length < 6) { return '密码格式错误' } else { return '' } } },
methods: { login () { if (this.tel === '' || this.teltip !== '') { this.tip = '手机号格式错误' return } if (this.password === '' || this.passwordtip !== '') { this.tip = '密码格式错误' return } // 登录 axios.post('/users/login', { tel: this.tel, password: this.password }).then(res => { console.log(res.data) /*** * 10086 未注册 * 10100 密码错误 * 10010 登录成功 */ if (res.data.code === '10086') { this.tip = '该用户未注册,请先注册' } else if (res.data.code === '10100') { this.tip = '密码错误' } else { // 此时为登录成功,获取token信息存入本地 this.tip = '' const token = res.data.token localStorage.setItem('token', token) } }) } }
<div class="content"> <!-- 使用组件 --> <Prolist v-if="flag" :prolist="prolist"/> <div v-else> 登录以后才能看到更多的信息 <router-link to="/login">登录</router-link> </div> </div>
data () { return { prolist: [], flag: false } }, created () { axios.get('/pro?token=' + localStorage.getItem('token')).then(res => { console.log(res.data) if (res.data.code === '10119') { this.flag = false } else { this.flag = true this.prolist = res.data.data } }) }
<div class="content"> <div v-if="flag"> <img :src="proimg" alt=""> <h1>{{ proname }}</h1> <h3>{{ note }}</h3> <p>{{ price }}</p> <ul> <li v-for="item of commentlist" :key="item.commentid"> <h4>{{ item.username }} - {{ item.rating }}</h4> <p>{{ item.note }}</p> </li> </ul> </div> <div v-else> 登录以后才能看到更多的信息 <router-link to="/login">登录</router-link> </div> </div>
data () { return { flag: false, proid: '', proname: '', proimg: '', price: '', note: '', commentlist: [] } }, created () { console.log(this.$route.query) const proid = this.$route.query.proid axios.get('/pro/detail?proid=' + proid + '&token=' + localStorage.getItem('token')).then(res => { console.log(res.data) if (res.data.code === '10119') { this.flag = false } else { this.flag = true this.proid = res.data.data.proid this.proname = res.data.data.proname this.proimg = res.data.data.proimg this.price = res.data.data.price this.note = res.data.data.note } }) axios.get('/comment?proid=' + proid + '&token=' + localStorage.getItem('token')).then(res => { // console.log(res.data.data) if (res.data.code === '10119') { this.flag = false } else { this.flag = true this.commentlist = res.data.data } }) }
找到UI库API文档,安装模块,找到快速上手,按照步骤配置UI库,复制-粘贴-删除-修改前端
以vant为例: https://youzan.github.io/vant/#/zh-CN/introvue
cnpm i vant -Sios
cnpm i babel-plugin-import -Dgit
修改babel.config.js文件es6
module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ], // +++++++++++++++++ plugins: [ ['import', { libraryName: 'vant', libraryDirectory: 'es', style: true }, 'vant'] ] }
配置文件的修改,必定要记得从新启动服务器github
https://youzan.github.io/vant/#/zh-CN/swipeweb
app.use((req, res, next) => { if (req.url !== '/users/login' && req.url !== '/users/register' && req.url !== '/banner') {} })
import Vue from 'vue' import { Swipe, SwipeItem } from 'vant' Vue.use(Swipe).use(SwipeItem) // 使用该语句,组件就无需再单独注册
data () { return { bannerlist: [], // ************* prolist: [], flag: false } }, created () { // ++++++++++++++++++++ axios.get('/banner').then(res => { console.log(res.data) this.bannerlist = res.data.data }) axios.get('/pro?token=' + localStorage.getItem('token')).then(res => { console.log(res.data) if (res.data.code === '10119') { this.flag = false } else { this.flag = true this.prolist = res.data.data } }) }
<!-- 轮播图 --> <van-swipe :autoplay="3000" indicator-color="white"> <van-swipe-item v-for="item of bannerlist" :key="item.bannerid"> <img :src="item.img" alt=""> </van-swipe-item> </van-swipe>
https://youzan.github.io/vant/#/zh-CN/goods-actionsql
引入组件
修改
views/address/index.vue + 路由
{ path: '/address', name: 'address', components: { // 一个路由 对象两个位置发生变化 default: () => import('@/views/address/index.vue') } }
<template> <div class="box"> <header class="header">城市选择</header> <div class="content"> <van-index-bar> <van-index-anchor v-for="(item, index) of list" :key="index" :index="item.letter" > <van-cell v-for="itm of item.cities" :key="itm.id" :title="itm.name" /> </van-index-anchor> </van-index-bar> </div> </div> </template> <script> import Vue from 'vue' import { IndexBar, IndexAnchor, Cell } from 'vant' import axios from 'axios' Vue.use(IndexBar).use(IndexAnchor) Vue.use(Cell) export default { data () { return { list: [] } }, created () { axios.get('/city.json').then(res => { console.log(res.data) this.list = res.data }) } } </script> <style lang="scss" scoped> .van-index-bar { height: 100%; overflow: auto; } </style>
https://youzan.github.io/vant/#/zh-CN/list
import axios from 'axios' import Vue from 'vue' import { Swipe, SwipeItem, List } from 'vant' // ++++++ // 引入列表的组件 ---- es6中的模块化 import Prolist from '@/components/Prolist.vue' Vue.use(Swipe).use(SwipeItem) Vue.use(List) // ++++++
data () { return { bannerlist: [], prolist: [], flag: false, // ++++++++ loading: false, // 表示当前是否是正在加载,若是为真,表示能够请求数据,请求成功置为false // ++++++++ finished: false, // 为true表示全部数据都已加载完毕 // +++++++++ pageCode: 1 // 页码 从1开始,默认值为0 } }, methods: { onLoad () { // 页面触底 触发该函数,能够加载下一页的数据 this.loading = true // 开始加载数据 axios.get('/pro?limitNum=10&pageCode=' + this.pageCode + '&token=' + localStorage.getItem('token')).then(res => { console.log(res.data) this.loading = false // 表示加载结束 this.pageCode++ // 加载结束 页码加1 if (res.data.code === '10119') { // 未登陆 this.flag = false } else { // 能够拿到数据 this.flag = true // 判断有没有数据,若是没有数据,告诉没有数据了,若是有数据,拼接数据 if (res.data.data.length === 0) { this.finished = true // 表示数据已经加载完毕 } else { // 拼接数据 ----- 数组的合并 // arr.concat(arr1) // [...arr, ...arr1] es6中的合并数组 this.prolist = [...this.prolist, ...res.data.data] } } }) } }
<!-- 使用组件 --> <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <Prolist v-if="flag" :prolist="prolist"/> <div v-else> 登录以后才能看到更多的信息 <router-link to="/login">登录</router-link> </div> </van-list>
https://youzan.github.io/vant/#/zh-CN/pull-refresh
import axios from 'axios' import Vue from 'vue' import { Swipe, SwipeItem, List, PullRefresh } from 'vant' // ++++++ // 引入列表的组件 ---- es6中的模块化 import Prolist from '@/components/Prolist.vue' Vue.use(Swipe).use(SwipeItem) Vue.use(List) Vue.use(PullRefresh) // ++++++
data () { return { bannerlist: [], prolist: [], flag: false, loading: false, // 表示当前是否是正在加载,若是为真,表示能够请求数据,请求成功置为false finished: false, // 为true表示全部数据都已加载完毕 pageCode: 1, // ++++++++++++++ isLoading: false // 在不在刷新,若是为真,能够请求数据,请求完毕设置为false } }, methods: { onLoad () { // 页面触底 触发该函数,能够加载下一页的数据 this.loading = true // 开始加载数据 axios.get('/pro?limitNum=10&pageCode=' + this.pageCode + '&token=' + localStorage.getItem('token')).then(res => { console.log(res.data) this.loading = false // 表示加载结束 this.pageCode++ // 加载结束 页码加1 if (res.data.code === '10119') { // 未登陆 this.flag = false } else { // 能够拿到数据 this.flag = true // 判断有没有数据,若是没有数据,告诉没有数据了,若是有数据,拼接数据 if (res.data.data.length === 0) { this.finished = true // 表示数据已经加载完毕 } else { // 拼接数据 ----- 数组的合并 // arr.concat(arr1) // [...arr, ...arr1] es6中的合并数组 this.prolist = [...this.prolist, ...res.data.data] } } }) }, // +++++++++++++++++++++++++ onRefresh () { // 下拉触发此函数 this.isLoading = true // 表示能够请求第一页(默认)的数据 axios.get('/pro?token=' + localStorage.getItem('token')).then(res => { console.log(res.data) this.isLoading = false // 表示下拉刷新请求函数结束 if (res.data.code === '10119') { this.flag = false } else { this.flag = true this.finished = false // 表示还能够继续上拉加载 this.pageCode = 1 // 下拉刷新即加载第一页数据,刷新以后重置页码 this.prolist = res.data.data // 下拉刷新就是直接替换列表 } }) } }
<div class="content"> <van-pull-refresh v-model="isLoading" @refresh="onRefresh"> <!-- 轮播图 --> <van-swipe :autoplay="3000" indicator-color="white"> <van-swipe-item v-for="item of bannerlist" :key="item.bannerid"> <img :src="item.img" alt=""> </van-swipe-item> </van-swipe> <!-- 使用组件 --> <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <Prolist v-if="flag" :prolist="prolist"/> <div v-else> 登录以后才能看到更多的信息 <router-link to="/login">登录</router-link> </div> </van-list> </van-pull-refresh> </div>
谁有滚动条,谁的scrollTop为0,跟布局相关
弹性盒布局 -- content -- 产生滚动条
//at.alicdn.com/t/font_1476238_uph8zgimp3.css
<span class="backtop iconfont icon-fanhuidingbu"></span> .backtop { position: fixed; bottom: 60px; right: 10px; font-size: 30px; }
<div class="content" id="content"></div> <span @click="backtop" class="backtop iconfont icon-fanhuidingbu"></span> backtop () { document.getElementById('content').scrollTop = 0 }
<span @click="backtop" v-show="topflag" class="backtop iconfont icon-fanhuidingbu"></span> data () { return { bannerlist: [], prolist: [], flag: false, loading: false, // 表示当前是否是正在加载,若是为真,表示能够请求数据,请求成功置为false finished: false, // 为true表示全部数据都已加载完毕 pageCode: 1, isLoading: false, // 在不在刷新,若是为真,能够请求数据,请求完毕设置为false // +++++++++++++ topflag: false // 默认不显示返回顶部图标 } }, watch: { pageCode (newval, oldval) { if (newval > 2) { // 由于刚开始会默认加载一次数据,加载完以后页码已为2 this.topflag = true } else { this.topflag = false } } }, methods: { backtop () { document.getElementById('content').scrollTop = 0 this.topflag = false // ++++++++++++++++++++ } }