vue3笔记
大约 3 分钟
npm 镜像
npm config set registry https://registry.npmmirror.com
# 取消
npm config rm registry
vite 创建项目
yarn create vite app-name --templet=vue
yarn add vue-router@4 pinia axios vuetify vite-plugin-vuetify @mdi/font
vue-router
https://router.vuejs.org/zh/installation.html
yarn add vue-router@4
// route/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Index from '@/views/index/index'
const routes = [
{
path: '/',
name: 'index',
component: Index
}
]
const router = createRouter({
routes,
history: createWebHistory(),
scrollBehavior() {
return { top: 0 }
}
})
router.beforeEach((to, form, next) => {
let token = LocalStorage.get(EnumData.tokenLabel)
if (token === null && to.path !== "/login") {
router.push({path: "/login"})
} else {
next();
}
})
export default router
// main.js
import router from './route/index.js'
createApp(App)
.use(router)
.mount('#app')
// app.vue
<template>
<router-view v-slot="{Component,route}">
<keep-alive>
<component :is="Component"/>
</keep-alive>
</router-view>
</template>
pinia
https://pinia.vuejs.org/zh/getting-started.html
yarn add pinia
加载:mian.js
import {createPinia} from "pinia"
.use(createPinia())
import { defineStore } from "pinia"
import { movieApiList, userInfo, websiteInfo } from "../api/index.js";
import LocalStorage from "../utils/LocalStorage.js";
import EnumData from "../utils/EnumData.js";
export const useWebsiteStore = defineStore("websiteStore", {
state: () => {
return {
website: {
api_parse_url: "",
api_url: "",
api_key: "",
cloud_url: "",
download_data: "",
name: "聚合影视",
author: "OrangBus",
url: "https://orangbus.cn",
ws_url: "localhost:3030",
plan: 0,
version: 0,
cloud_version: 0
},
}
},
actions: {
getWebsite() {
websiteInfo().then(res => {
if (res.code === 200) {
this.website = res.data;
LocalStorage.set(EnumData.websiteLabel, res.data)
}
});
},
setWebsite(website) {
this.website = website
LocalStorage.set(EnumData.websiteLabel, website)
}
}
})
export const useUserStore = defineStore("userStore", {
state: () => {
return {
user: {
id:0
},
}
},
actions: {
getUserInfo() {
userInfo().then(res => {
if (res.code === 200) {
this.user = res.data;
}
});
},
setUserInfo(data) {
this.user = data;
LocalStorage.set(EnumData.userLabel, data)
},
}
})
axios
https://axios-http.com/zh/docs/intro
yarn add axios
拦截器
import axios from "axios";
import LocalStorage from "../utils/LocalStorage.js";
import EnumData from "../utils/EnumData.js";
import snackbar from "../utils/snackbar.js";
axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
axios.defaults.withCredentials = true;
axios.defaults.timeout = 30000;
axios.interceptors.request.use((config)=>{
config.headers['Authorization'] = 'Bearer ' + LocalStorage.get(EnumData.tokenLabel);
config.headers['Content-Type'] = "multipart/form-data";
return config;
},(error)=>{
return Promise.reject(error);
})
axios.interceptors.response.use((response)=>{
const status = response.data.code;
switch (status){
case 200:
case 202:
return response.data;
break;
default:
snackbar.error("请求错误,刷新重试");
break;
}
return response;
},(error)=>{
const status = error.response.status;
if (status === 419){
return error.response.data;
}
if (error.message.includes("timeout")){
snackbar.error("请求超时,请重试");
}
return Promise.reject(error);
})
export default axios;
vuetify
yarn add vuetify
import { createApp } from 'vue'
// Vuetify
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import "@mdi/font/css/materialdesignicons.min.css";
// Components
import App from './App.vue'
const vuetify = createVuetify({
components,
directives,
icons: {
defaultSet: 'mdi',
aliases,
sets: {
mdi,
},
},
theme: {
defaultTheme: 'light', // 'system' | 'light' | 'dark'
},
})
createApp(App).use(vuetify).mount('#app')
图标
yarn add @mdi/font
消息提示
yarn add vue-toastification@next
package推荐
vue三剑客
npm i axios vue-router vuex
mdui
npm i mdui --save
获取浏览器信息
https://www.npmjs.com/package/ua-parser-js
npm i ua-parser-js
获取env值
// .env
app_name=orangbus
process.env.app_name
代理
"devServer" : {
"port" : 80,
"disableHostCheck" : true,
"proxy" : {
"/m1" : {
"target" : "http://api.000zy.com/provide/vod",
"changeOrigin" : true,
"secure" : false
},
"/m2" : {
"target" : "https://caiji.naichaapi.com/inc/apijson_vod.php",
"changeOrigin" : true,
"secure" : false
},
"/m3" : {
"target" : "https://m3u8.bdxzyapi.com/api.php/provide/vod",
"changeOrigin" : true,
"secure" : false
},
"/m4" : {
"target" : "http://www.kuaibozy.com/api.php/provide/vod",
"changeOrigin" : true,
"secure" : false
}
}
}
vue+vite 配置代理
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server:{
proxy:{
"/ai": {
target: "http://localhost:11434",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/ai/, "/api/"),
},
}
}
})
vue3缓存
前进请求数据,返回定位到之前的页面
文件上传
gin steam输出
func sseHandler(c *gin.Context) {
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
for i := 0; ; i++ {
// 发送事件数据
data := fmt.Sprintf("data: %d - %s\n\n", i, time.Now().Format(time.RFC1123))
_, err := c.Writer.WriteString(data)
if err != nil {
c.Error(err)
return
}
// 刷新缓冲区,将数据发送到客户端
c.Writer.Flush()
// 每秒发送一次数据
time.Sleep(1 * time.Second)
}
laravel steam 输出
public function sseData()
{
return response()->stream(function (){
$data = "服务器发送事件 (SSE) 可以在 Laravel 应用程序(服务器)和浏览器(客户端)之间实现实时通信。这样,你就可以向用户推送更新,而无需不断刷新页面。以下是在 Laravel 中实现 SSE 的两种常见方法的分步指南。";
$total = mb_strlen($data,"UTF-8");
for ($i = 0; $i < $total; $i++) {
echo "data: ".mb_substr($data, $i, 1, 'UTF-8')."\n\n";
ob_flush();
flush();
// 如果停止或这关闭页面
if (connection_aborted()) {
break;
}
usleep(1000);
}
}, 200, [
'Cache-Control' => 'no-cache',
'Content-Type' => 'text/event-stream',
'Connection' => 'keep-alive',
]);
}
前端接收
const response = await fetch('http://127.0.0.1:7345/api/gpt/get', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
message: message.value,
role: role.value,
}),
});
if (!response.body) return;
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
var { value, done } = await reader.read();
if (done) break;
value = value?.replace('undefined', '')
console.log("received data -", value)
output.value += value?.replace('undefined', '')
}
sse接受数据返回
function getData(){
var source = new EventSource("/demo/sse/data");
source.onmessage = function (event) {
let item = document.getElementsByClassName("data")
item.innerHTML = event.data;
console.log(event.data);
};
source.onerror = function (event) {
console.log(event);
source.close()
};
}
