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 // ++++++++++++++++++++ } }