# go15 **Repository Path**: shiwjlinux/go15 ## Basic Information - **Project Name**: go15 - **Description**: No description available - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-05-18 - **Last Updated**: 2024-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # go15 ## 介绍 Vblog ## Apipost接口文档 避免通道, 有锁 回调 # vue ``` bash # 安装 npm install -g @vue/cli # 创建项目 npm create vue@latest Need to install the following packages: create-vue@3.10.4 Ok to proceed? (y) y > npx > create-vue Vue.js - The Progressive JavaScript Framework √ 请输入项目名称: ... vue-project √ 是否使用 TypeScript 语法? ... 否 / 是 √ 是否启用 JSX 支持? ... 否 / 是 √ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是 √ 是否引入 Pinia 用于状态管理? ... 否 / 是 √ 是否引入 Vitest 用于单元测试? ... 否 / 是 √ 是否要引入一款端到端(End to End)测试工具? » 不需要 √ 是否引入 ESLint 用于代码质量检测? ... 否 / 是 √ 是否引入 Prettier 用于代码格式化? ... 否 / 是 √ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是 正在初始化项目 D:\goProject\go15\skills\vue-project... 项目初始化完成,可执行以下命令: cd vue-project npm install npm run format npm run dev ``` # 响应式变量 reactive ref 组件 keep-alive 不会被销毁 watch 可以监听一个变量是否改变 # 两种语法 ``` bash innerText属性 vue {{ 变量 }} 标签属性中
testId=ref("test") onClick --> v-on:click :style 是一个对象 sytyleDivA1={ color: 'red', fontSize: '20px'} :class 是个数组 定义一个ref数组,动态class改变 classDivA1=ref([]) classDivA1.push('class1') classDivA1=['class1','class2'] v-model 双向绑定 ,一般用于表单, 绑定input的value v-bind: 缩写 : v-on: 缩写 @ v-bind:class 缩写 :class v-bind:style 缩写 :style !important 覆盖原来的样式 自定义指令 调用v-focus 定义vFocus v-show 是否显示 ,对象还存在 v-if 是否显示 ,对象不存在 ```js v-model 双向绑定 vue组件 vue vscode sni ``` # 前端页面 ## 路由设置 默认跳转登陆页 ```js import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'HomePage', redirect: { name: 'LoginPage' } }, { path: '/login', name: 'LoginPage', component: () => import('@/views/login/LoginPage.vue') }, { path: '/backend', name: 'BackendPage', component: () => import('@/views/backend/BackendPage.vue'), redirect: { name: 'BackendBlogsList' }, children: [ { path: 'blogs/list', name: 'BackendBlogsList', component: () => import('@/views/backend/blogs/ListPage.vue') }, { path: 'blogs/edit', name: 'BackendBlogsEdit', component: () => import('@/views/backend/blogs/EditPage.vue') } ] }, { path: '/frontend', name: 'FrontendPage', component: () => import('@/views/frontend/FrontendPage.vue'), children: [] } ] }) export default router ``` ## 基本样式 ```js vblog\ui\src\assets\main.css APP占满整个浏览器 #app { font-weight: normal; width: 100vw; height: 100vh; } vblog\ui\src\views\login\LoginPage.vue form信息 ``` ```js vblog\ui\src\main.js 引入图标库 // 图标库 import ArcoVueIcon from '@arco-design/web-vue/es/icon'; app.use(ArcoVueIcon) ``` ```js vblog\ui\src\views\login\LoginPage.vue ``` ## form验证 隐藏* ```js const rules = { username: [ { required: true, message: '用户名为必填项' } ], password: [ { required: true, message: '密码为必填项' } ] } ``` ![登陆页面](image.png) ## 提交后打印data,data{errors,values} ```js // 点击登陆时触发 const handleSubmit = async (data) => { // 没有errors时 if (!data.errors) { console.log(data.values) try { // 设置Loading状态 // 请求登陆接口 // 接收返回的数据 // 跳转后台页面 console.log() } catch (error) { // 登陆失败 console.log() } finally { // 不管是否登陆成功,取消Loading状态 } } } ``` ## button的loading状态 ```js 登陆 const loading=ref(false) ``` ![Loading状态](image-1.png) ## 配置axios ```js npm install axios vblog\ui\src\api\client.js import axios from "axios"; var httpClient = axios.create({ baseURL: 'http://127.0.0.1:9000/vblog/api/v1/', // baseURL:'', timeout:5000 }) export default httpClient ``` ## 添加函数 ```js vblog\ui\src\api\vblog.js import httpClient from './client' export var LOGIN = (data) => { return httpClient.post('tokens', data) } vue中调用 const resp = await LOGIN(data.values) console.log(resp) ``` ![跨域问题](image-2.png) ## 配置vite代理 ```js vblog\ui\vite.config.js server中添加proxy export default defineConfig({ plugins: [vue(), vueDevTools()], server: { host: '0.0.0.0', port: '3000', // open: true, proxy: { '/vblog/api/v1': 'http://127.0.0.1:9000/' // '/vblog' : 'http://127.0.0.1:9000/' } }, vblog\ui\src\api\client.js var httpClient = axios.create({ // 使用了vite代理 // baseURL: 'http://127.0.0.1:9000/vblog/api/v1/', baseURL:'', timeout:5000 }) vblog\ui\src\api\vblog.js export var LOGIN = (data) => { return httpClient.post('/vblog/api/v1/tokens', data) } ``` ![alt text](image-3.png) ## axios返回数据处理 ```js vblog\ui\src\api\client.js import axios from "axios"; var httpClient = axios.create({ // 使用了vite代理 // baseURL: 'http://127.0.0.1:9000/vblog/api/v1/', baseURL:'', timeout:5000 }) // httpClient // 请求时返回正常数据 或者 AxiosError // AxiosError 使用 interceptors拦截器 httpClient.interceptors.response.use( // 请求成功返回成功的数据 (response) => { return response.data }, // 请求失败返回错误信息 (error) => { return Promise.reject(error.response) } ) export default httpClient ``` ## 处理LOGIN结果 ```js vblog\ui\src\views\login\LoginPage.vue ``` ![alt text](image-4.png) ## 登陆成功 ```js vblog\ui\src\api\client.js httpClient.interceptors.response.use( // 请求成功返回成功的数据 (response) => { return response }, ``` 跳由跳转 ```js vblog\ui\src\views\login\LoginPage.vue import { useRouter } from 'vue-router' const router = useRouter() // 点击登陆时触发 const handleSubmit = async (data) => { // 没有errors时 if (!data.errors) { // console.log(data.values) try { // 设置Loading状态 // 请求登陆接口 // 接收返回的数据 // 跳转后台页面 loading.value = true // const resp = LOGIN(data.values) const resp = await LOGIN(data.values) // console.log(resp) if (resp.status === 200) { if (data.values.isRemember) { // 持久化存储 // resp.data } Message.success('登陆成功') // 跳转后台页面 router.push({ name: 'BackendPage' }) } } catch (error) { // 登陆失败 // console.log(error) Message.error(error.code + ' ' + error.message) } finally { // 不管是否登陆成功,取消Loading状态 loading.value = false } } } ``` ![alt text](image-5.png) ## 持久化存储 ```js 保存token信息 npm i @vueuse/core vblog\ui\src\stores\storage.js import { useStorage } from '@vueuse/core' const token = {} export default useStorage( 'my-store', token, localStorage, { mergeDefaults: true } ) vblog\ui\src\views\login\LoginPage.vue // 什么时候用{} 什么时候不用 import storage from '@/stores/storage' if (resp.status === 200) { // if (data.values.isRemember) {} // 持久化存储 // resp.data storage.value.token = resp.data Message.success('登陆成功') // 跳转后台页面 router.push({ name: 'BackendPage' }) } ``` ## 跳转到后台页面 ```js vblog\ui\src\views\backend\BackendPage.vue ``` ![alt text](image-6.png) ## 退出登录 ```js vblog\ui\src\api\vblog.js export var LOGOUT = (refreshToken) => { return httpClient.delete('/vblog/api/v1/tokens', { headers: { 'X-REFRESH-TOKEN': refreshToken } }) } vblog\ui\src\views\backend\BackendPage.vue ``` ![alt text](image-7.png) ## 侧边栏 ```js vblog\ui\src\views\backend\BackendPage.vue