vue3使用router
import Cookies from 'js-cookie';
import {
createRouter,
createWebHistory,
RouteRecordRaw,
Router,
} from 'vue-router'
import store from '../store';
import { getAdminInfoApi } from '../request/api'
import { ElMessage } from 'element-plus'
const routes: Array<RouteRecordRaw> = [
{
path: "/login",
name: "Login",
component: () =>
import(/* webpackChunkName: "About" */ "../views/login/Login.vue"),
},
// {
// path: "/ums",
// name: "ums",
// component: () =>
// import(/* webpackChunkName: "About" */ "../views/index/Index.vue"),
// children: [
// {
// path: "admin",
// name: "Admin",
// component: () => import(/* webpackChunkName: "cart" */ "../views/admin/admin.vue"),
// },
// ],
// },
];
const router: Router = createRouter({
history: createWebHistory(),
routes,
});
// 封装动态添加路由
const getRouter = ()=>{
store.dispatch('getAdminInfo').then(() => {
const menus = store.getters.getNewMenus
for (let k in menus) {
const newRoute: RouteRecordRaw = {
path: "/" + menus[k].name,
name: menus[k].name,
component: () =>import(/* webpackChunkName: "About" */ "../views/index/homepage.vue"),
redirect:"/"+ menus[k].name+'/'+menus[k].children[0].name,
children: []
}
for (let i = 0; i < menus[k].children.length; i++) {
newRoute.children?.push({
path: menus[k].children[i].name,
name: menus[k].children[i].name,
component: () =>
import(/* webpackChunkName: "About" */ `../views/${menus[k].name}/${menus[k].children[i].name}.vue`),
})
}
router.addRoute(newRoute)
}
router.addRoute({
path: "/",
name: "homepage",
component: () =>import("../views/index/homepage.vue"),
redirect:"/index",
children: [
{
path: "index",
name: "Index",
component: () => import(/* webpackChunkName: "cart" */ "../views/index/index.vue"),
},
],
})
})
}
// 前置导航守卫
router.beforeEach((to, from, next) => {
const token = Cookies.get('token')
// 判断是否有token
if (token && store.state.menus.length === 0) {
// console.log('menus为空');
getAdminInfoApi().then(res => {
// console.log(res);
// store.commit('updataments', res.data.menus)
getRouter()
next(to.path)
})
}else if(token && store.state.menus.length !== 0 && from.path ==='/login' && to.path==='/home'){
getRouter();
next('/index')
}else if(token && to.path==='/login'){
ElMessage.error('你已经登录了')
next(from)
} else if(!token && to.path !=='/login'){
ElMessage.error('你还没有登录哦,正在跳转登录页')
next('/login')
} else {
next()
}
})
export default router;
使用
import { useRouter } from 'vue-router'
let router = useRouter()
router.push('/home')
vue3使用store(vuex)
import { createStore } from "vuex";
import { App } from "vue";
import { getAdminInfoApi} from '../request/api'
interface state{
menus:Menobj[]
username:String
}
interface Menobj{
parentId:number;
id:number;
children?:Menobj[]
}
interface NewMenus {
[key:number]:Menobj
}
const store =createStore<state>({
state(){
return{
menus:[],
username:""
}
},
getters:{
getNewMenus(state){
const newMenus:NewMenus = {}
const menus = state.menus
for(let i=0;i<menus.length;i++){
if(menus[i].parentId===0){
newMenus[menus[i].id] = {...menus[i],children:newMenus[menus[i].id]?.children || []}
}else {
let parentId = menus[i].parentId;
newMenus[parentId] = newMenus[parentId] || {};
newMenus[parentId].children = newMenus[parentId].children || [];
newMenus[parentId].children?.push(menus[i])
}
}
return newMenus
}
},
mutations:{
updataments(state,menus){
state.menus = menus
},
upNewName(state,username){
state.username = username
}
},
actions:{
getAdminInfo({commit}){
return new Promise((resolve,reject)=>{
getAdminInfoApi().then(res=>{
if(res.code===200){
commit('updataments',res.data.menus)
commit('upNewName',res.data.username)
resolve(res.data)
}else{
reject(res)
}
})
})
}
},
modules:{}
})
export const initStore = (app:App<Element>)=>{
app.use(store)
}
export default store
使用
import { useStore } from 'vuex'
let store = useStore()
store.state.menus
vue3存储cookies
https://www.npmjs.com/package/js-cookie
下载
npm i js-cookie
import Cookies from 'js-cookie'
//存储
Cookies.set('token', res.data.tokenHead + res.data.token, { expires: 7 })
//获取
Cookies.get('token')
vue3使用request
api.ts
import request from './request'
import qs from 'qs'
interface AdminLoginData {
password: string
username: string
}
type ProminseRes<T> = Promise<ManageResult<T>>
interface ManageResult<T = {}> {
code?: number;
data: T
message?: string
errno?: number
}
//登录返回token
interface AdminLoginRes {
token: string;
tokenHead: string;
}
// 当前用户信息
interface AdminInfoRes{
menus:[],
username:String
}
// 用户列表
interface AdminListRes{
list:[{
status:number | undefined;
id:number | undefined
}],
total:number,
totalPage:number
}
interface AdminListData {
keyword:string
pageNum: number
pageSize: number
}
// 修改账号状态
// 推荐品牌
interface HomeBrandList{
brandName?:string
pageNum: number
pageSize: number
recommendStatus?:number
}
// 登录功能
export const LoginApi = (data: AdminLoginData):ProminseRes<AdminLoginRes> => request.post('/admin/login', data)
// 获取用户信息
export const getAdminInfoApi = ():ProminseRes<AdminInfoRes>=>request.get('/admin/info')
// 根据用户名或姓名分页获取用户列表
// export const getAdminlistApi = (data:AdminListData):ProminseRes<AdminListRes>=>request.get(`/admin/list?pageNum=${data.pageNum}&pageSize=${data.pageSize}`)
export const getAdminlistApi = (data:AdminListData):ProminseRes<AdminListRes>=>request.get('/admin/list',{params:data})
// 修改指定用户信息
export const AdminUpdateApi = (data: AdminObjInfo):ProminseRes<number> => request.post(`/admin/update/${data.id}`, data)
// 修改帐号状态
export const AdminupdateStatusApi = (id:number,status:number):ProminseRes<number> => request.post(`/admin/updateStatus/${id}/?status=${status}`)
// 添加用户
export const AdminregisterApi = (data: AdminObjInfo):ProminseRes<object> => request.post('/admin/register', data)
// 获取所有角色
export const rolelistAllApi = ():ProminseRes<[]>=>request.get('/role/listAll')
// 获取当前角色
export const roleApi = (adminId:number|undefined):ProminseRes<[{id:number}]>=>request.get(`/admin/role/${adminId}`)
// 给用户分配角色
export const roleupdateApi= (data:{adminId:number;roleIds:string}):ProminseRes<object>=>request.post('/admin/role/update',null,{params:data})
// 分页查询推荐品牌
export const HomeBrandList= (data:HomeBrandList):ProminseRes<AdminListRes>=>request.get('/home/brand/list',{params:data})
request.ts
import axios from "axios";
import Cookies from 'js-cookie'
let instance = axios.create({
baseURL: "http://120.24.64.5:8088/mall-admin",
timeout: 5000
});
instance.interceptors.request.use(function (config) {
let token =Cookies.get('token')
if(token){
//添加请求头
config.headers = config.headers || {}
config.headers.Authorization = token
}
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response.data;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default instance
vue2使用router
import Vue from 'vue'
import VueRouter from 'vue-router'
import {wechatUsers} from '../request/httpApi'
import store from '../store'
import bus from "../components/bus"
Vue.use(VueRouter)
const routes = [
{
path: '/index',
name: 'index',
component: () => import(/* webpackChunkName: "index" */ '../views/index.vue')
},
{
path: '/goods',
name: 'goods',
component: () => import(/* webpackChunkName: "goods" */ '../components/Goods.vue')
},
// {
// path: '/user',
// name: 'user',
// component: () => import(/* webpackChunkName: "user" */ '../views/User.vue')
// },
{
path: '/user',
name: 'user',
redirect:'/user/cart',
component: () => import(/* webpackChunkName: "user" */ '../components/User.vue'),
children:[
{
path: 'cart',
name: 'cart',
component: () => import(/* webpackChunkName: "cart" */ '../components/Cart.vue')
},
]
},
{
path: '/detail/:pid',
name: 'Detail',
component: () => import(/* webpackChunkName: "user" */ '../views/Detail.vue')
},
// {
// path: '/about',
// name: 'About',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//全局导航钩子
router.beforeEach((to,from ,next)=>{
const token = localStorage.getItem('token')
const userinfo = store.state.userInfo
const code = to.query.code
if(token && !userinfo){
// getUserProfiles().then(res=>{
// if(res.code===0){
// store.commit('getUserInfo' ,res.data)
// }
// })
store.dispatch('getdatauserInfo')
next()
}else if(code && !token){
wechatUsers({code}).then(res=>{
if(res.code===0){
localStorage.setItem("token", res["x-auth-token"]);
store.dispatch('getdatauserInfo').then(res=>{
//替换掉路径上的code参数
router.replace(to.path)
})
next()
}else if(res.code ===407){
bus.$emit("loginFn", true);
bus.$emit("uuid", res.uuid);
}
})
}else{
next()
}
})
export default router
要在main.js中全局引入
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'reset-css'
import toast from './components/Toast'
import SlideVerify from 'vue-monoplasty-slide-verify';
Vue.use(SlideVerify);
Vue.config.productionTip = false
Vue.prototype.$toast = toast
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
使用
//路由跳转
this.$router.push
//获取参数
this.$route.params 带/的地址或者是push跳转
this.$route.query 带?的地址
vue2使用store(vuex)
import Vue from 'vue'
import Vuex from 'vuex'
import {getUserProfiles} from '../request/httpApi'
import store from '../store'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userInfo:null
},
mutations: {
getUserInfo(state,userInfo){
state.userInfo = userInfo
}
},
actions: {
getdatauserInfo({commit}){
return new Promise((resolve,reject)=>{
getUserProfiles().then(res=>{
if(res.code===0){
commit('getUserInfo' ,res.data)
resolve(res.data)
}else{
reject(res.message)
}
})
})
}
},
modules: {
},
getters:{
},
getters:{
}
})
要在main.js中全局引入
使用
//拿vuex中的数据
this.$store.state.userInfo
//修改vuex中的数据
//mutations进行修改
this.$store.commit('getUserInfo' , res.data)
//使用actions的方法
this.$store.dispatch("getdatauserInfo").then((res) => {
this.cancelFn();
});
vue2使用localStorage本地存储
//存入
localStorage.setItem("token", res["x-auth-token"]);
//获取
localStorage.getItem('token')
//清除
localStorage.removeItem("token");
vue2使用bus
bus.js
import Vue from 'vue'
export default new Vue()
引入
//传参
bus.$emit("loginFn", true);
//接收
bus.$on("loginFn", (data) => {
this.showData = data;
console.log("222");
});
微信扫码登录
微信扫码布局与配置
在 public/index.html
的 head
中:
<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
在登录框中代码中添加一个div,这个div是用来存放微信二维码所在的iframe的:
<div id="weixin"></div>
在 api.js
中:
// 微信登录(这个接口必须用qs对数据进行格式化)
export const WeixinLoginApi = (params) => request.post(`/wechatUsers/PCLogin`, qs.stringify(params));
在切换到 微信扫码登录
的事件中:
// 点击了微信扫码登录
weixinClickFn() {
let _this = this;
new WxLogin({
id: "weixin",
appid: "wx67cfaf9e3ad31a0d", // 这个appid要填死
scope: "snsapi_login",
// 扫码成功后重定向的接口
redirect_uri: "https://sc.wolfcode.cn/cms/wechatUsers/shop/PC",
// state填写编码后的url
state: encodeURIComponent(window.btoa(process.env.VUE_APP_STATE_URL + _this.$route.path)),
// 调用样式文件 base64格式
href: "",
});
},
#* 环境变量 (不一定要进行)
上面的process.env.VUE_APP_STATE_URL是环境变量。书写方式:
在项目根目录新建
.env.prod
与.env.dev
:# .env.dev NODE_ENV=development VUE_APP_BASE_URL=/ VUE_APP_STATE_URL=http://127.0.0.1:8080 # .env.prod NODE_ENV = production VUE_APP_BASE_URL = 'http://codesohigh.com/store-pc/#' VUE_APP_STATE_URL = 'http://codesohigh.com/store-pc/#' Copied!
然后修改
package.json
中:{ "scripts": { "serve": "vue-cli-service serve --mode dev", "build": "vue-cli-service build --mode prod" }, } Copied!
重跑项目即可。
当你还没写href的时候,会发现iframe样式是无法改变的,因此我们需要借助 node+css
来实现css转base64:
在 src
下新建 utils
文件夹,并且在其中新建: data-url.js
与 wxlogin.css
:
/* wxlogin.css */
.impowerBox .title, .impowerBox .info{
display: none;
}
.impowerBox .qrcode{
margin-top: 20px;
}
然后控制台运行:
cd src/utils/
node data-url.js
得到一段base64转码字符串:
data:text/css;base64,LmltcG93ZXJCb3ggLnRpdGxlLCAuaW1wb3dlckJveCAuaW5mb3sNCiAgICBkaXNwbGF5OiBub25lOw0KfQ0KDQouaW1wb3dlckJveCAucXJjb2Rlew0KICAgIG1hcmdpbi10b3A6IDIwcHg7DQp9DQoNCg==
然后粘贴到 href
中。最终效果:
登录滑动拼图验证
插件参考:https://gitee.com/monoplasty/vue-monoplasty-slide-verify(opens new window)
#1、安装插件
npm install --save vue-monoplasty-slide-verify
# yarn安装方式
yarn add vue-monoplasty-slide-verify
#2、入口文件引入
import SlideVerify from 'vue-monoplasty-slide-verify' // 拼图验证码
Vue.use(SlideVerify)
#3、组件引用
<template>
<slide-verify :l="42" :r="20" :w="362" :h="140" @success="onSuccess" @fail="onFail" @refresh="onRefresh" :style="{ width: '100%' }" class="slide-box" ref="slideBlock" :slider-text="msg"></slide-verify>
</template>
<script>
export default {
data() {
return {
msg: "向右滑动"
};
},
methods: {
// 拼图成功
onSuccess(times) {
let ms = (times / 1000).toFixed(1);
this.msg = "login success, 耗时 " + ms + "s";
},
// 拼图失败
onFail() {
this.onRefresh(); // 重新刷新拼图
},
// 拼图刷新
onRefresh() {
this.msg = "再试一次";
},
// 点击登录按钮
submitFn(formName) {
if (this.msg == "再试一次" || this.msg == "向右滑动") {
console.log("请滑动拼图");
} else {
console.log("开始登录");
}
},
},
};
</script>
<style lang="less" scoped>
/deep/.slide-box {
width: 100%;
position: relative;
box-sizing: border-box;
canvas {
position: absolute;
left: 0;
top: -140px;
display: none;
width: 100%;
box-sizing: border-box;
}
.slide-verify-block{
width: 85px;
height: 136px;
}
.slide-verify-refresh-icon {
top: -140px;
display: none;
}
&:hover {
canvas {
display: block;
}
.slide-verify-refresh-icon {
display: block;
}
}
}
</style>
vue2解决跨域(代理配置)
//对 vue.config.js 进行配置:
module.exports = {
devServer: {
port: 3000,
proxy: {
'/api': {
//要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理(简单来说:转发的目标服务器和端口)
target: "http://kumanxuan1.f3322.net:8001/",
//pathRewrite是使用proxy进行代理时,对请求路径进行重定向以匹配到正确的请求地址
// '^/api': '/api' // 这种接口配置出来 http://XX.XX.XX.XX:8083/api/login
//'^/api': '/' 这种接口配置出来 http://XX.XX.XX.XX:8083/login
pathRewrite: {
'^/api': ''
}
}
}
}
}
vue2中ref和$refs
<div ref="testDom">11111</div>
console.log(this.$refs.testDom)
//本页面获取dom元素
//获取子组件中的data
//调用子组件中的方法
//子组件调用父组件方法
this.$emit("refreshData");获取父组件的方法
this.$refs.hello.open();再调用子组件的方法
vue2注册组件(局部)
//引入
import Header from './heard'
import Nav from './nav'
//注册
export default {
//组件注册
components:{
Header,
Nav,
// Good
}
}
//使用
<Header></Header>
<Nav></Nav>
vue3注册组件(局部)
//引入组件
import MyCom from './components/Mycom.vue'
//直接使用
<template>
<!-- 局部组件 -->
<MyCom></MyCom>
</template>