# 点击时获取事件对象
<template>
<button @click="test(1,2,$event)">按钮</button>
</template>
<script lang="ts" setup>
function test(a:number,b:number,c:Event){
//获取事件对象
console.log(c)
}
</script>
# 跨域参数配置
# 跨域相关参数
withCredentials:是否允许带cookie,true时服务端需要设置SupportsCredentials=true
import axios from 'axios'
import router from './../router'
import comm from './comm'
//axios.defaults.baseURL='/api';
const myAxios = axios.create({
// 只要发送axios请求,就在请求前加入/api的开头,例如 /zzz/one -> /api/zzz/one
baseURL: '/api',
// 设置超时时间 5s
timeout: 10000,
responseType: 'json',
// 是否允许带cookie,true时服务端需要设置SupportsCredentials
withCredentials: false,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
}
})
// POST传参序列化(添加请求拦截器)
myAxios.interceptors.request.use(
config => {
// 在发送请求之前做某件事
if (config.method === 'post' || config.method === 'put' || config.method === 'delete') {
// 序列化
const data = new FormData()
Object.keys(config.data).forEach(item => {
data.append(item, config.data[item])
})
config.data = data
}
if (localStorage.getItem('token')) {
config.headers.Authorization = localStorage.token
}
console.log(config.data)
return config
},
error => {
comm.toast(error.data.message)
return Promise.reject(error.data.message)
}
)
// 返回状态判断(添加响应拦截器)
myAxios.interceptors.response.use(
res => {
// 对响应数据做些事
if (res.data && res.data.code !== 1) {
comm.toast(res.data.msg)
return Promise.reject(res.data.msg)
}
return res.data
},
error => {
// 若是发现有鉴权的基础信息
if (localStorage.getItem('loginUserBaseInfo')) {
// 并且当前的时间大于服务器过期的时间
const loginUserBaseInfo = window.localStorage.getItem('loginUserBaseInfo')
const lifeTime = JSON.parse(loginUserBaseInfo).lifeTime * 1000
const nowTime = new Date().getTime()
if (nowTime > lifeTime) {
localStorage.removeItem('loginUserBaseInfo')
comm.toast('登录状态信息过期,请重新登录')
router.push({
path: '/login'
})
}
} else {
console.log(error)
// 服务器状态码不是200的情况,这些自定义
comm.toast(error.response.data.Message)
}
return Promise.reject(error.response)
}
)
export default myAxios
devServer: {
proxy: {
// 二级目录的一定要写在前面
'/api/wfs': {
target: 'http://localhost:8000',
changeOrigin: true,
pathRewrite: {
'^/dev-api/wfs': ''
},
logLevel: 'debug', // 可在控制台打印真实地址
},
'/api': {
disableHostCheck:true, // 当设置为true时,此选项将绕过主机检查
// 默认情况下是/,所以您可以作为http://localhost:8080使用
// 更改为 /assets/ 就变为 http://localhost:8080/assets
publicPath: '/assets/',
target: 'http://expo.sdxsk.com/api', //请求接口域名
ws: true,
secure: false,
// 是否允许跨域
changOrigin: true,
// 如果配置了axios的baseURL为'/api',在这里需要用空字符串代替
pathRewrite: {
'^/api': ''
}
}
}
}
// 这个是对所有的接口都代理的,不止是检测到 /api 的接口
// 当请求了前端不存在的资源时,那么该请求会转发给服务器(优先匹配前端资源)
devServer: {
proxy: 'http://e.dxy.net'
}
在Vue项目中配置了代理,但是部署之后不生效,并且报404
这是因为Vue配置的代理仅在本地开发下有效,部署之后,需要:
- 在nginx中进行配置代理
- 或者后端配置跨域
# vue2相关设置
devServer: {
host: '0.0.0.0',
port: port,
open: true,
proxy: {
[process.env.VUE_APP_BASE_API]: {
target: `http://128.169.21.56:8081`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
disableHostCheck: true
}
# vue3相关设置
server: {
host: "localhost",
port: 3002,
proxy: {
// "/api/":
[ENV.VITE_API_URL]: {
target: "http://125.125.35.24:8088",
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, "")
rewrite: (p) => p.replace(RegExp(`^${ENV.VITE_API_URL}`), "")
}
}
}
# 监听元素变化
noMounted(() => {
// 创建一个观察器实例并传入回调函数
domOberver = new MutationObserver((mList, ob) => {
autoNiceHeight()
})
// 观察器的配置(需要观察什么变动)
const config = {
attributes: true,
childList: true,
subtree: true
}
// 配置开始观察的目标节点
domObserver.observe(dialogRef.value, config)
})
onUnmounted(() => {
// 停止观察
domObserver.disconnect()
})
function autoNiceHeight(){
const isExceed = warpperEle.offsetHeight <
dialogRef.value.offsetHeight + dialogRef.value.offsetTop
if(isExceed){
const niceHeight = warpperEle.offsetHeight - dialogRef.value.offsetTop
dialogRef.value.style.height = autoUnit(niceHeight)
}
}
# 找不到模块"./XXX.vue"或其相应的类型声明
该问题是由于ts无法识别.vue文件导致的
- 在最外层的目录下新建一个env.d.ts文件
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
declare module 'v-annotator'
- 最简版的方法
# 找到对应的eslint 的扩展 将它关闭,或者是将对应的设置关闭,不过这对于团队开发的话。会有所影响
# 和Iframe的通信
# 父组件向iframe发送消息
<template>
<div>
<iframe ref="iframe" :src="iframeSrc"></iframe>
<button @click="sendMessageToIframe">发送消息到iframe</button>
</div>
</template>
<script>
export default {
data() {
return {
iframeSrc: 'https://example.com/iframe-page' // 替换为实际的iframe页面地址
}
},
methods: {
sendMessageToIframe() {
const message = { type: 'parentMessage', data: '这是来自父组件的消息' }
this.$refs.iframe.contentWindow.postMessage(message, '*')
}
}
}
</script>
# iframe中的页面接收父组件发送的消息
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>IFrame Page</title>
</head>
<body>
<script>
window.addEventListener('message', event => {
if (event.origin === 'https://your-parent-app-url') { // 替换为实际的父应用地址
const message = event.data
console.log('接收到来自父组件的消息:', message)
// 在这里根据消息类型进行相应的处理
}
})
</script>
</body>
</html>
# iframe向父组件发送消息
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>IFrame Page</title>
</head>
<body>
<button onclick="sendMessageToParent()">发送消息到父组件</button>
<script>
function sendMessageToParent() {
const message = { type: 'iframeMessage', data: '这是来自iframe的消息' }
window.parent.postMessage(message, '*')
}
</script>
</body>
</html>
# 父组件接收iframe发送的消息
<script>
export default {
// ...
mounted() {
window.addEventListener('message', event => {
if (event.origin === 'https://example.com') { // 替换为实际的iframe页面地址
const message = event.data
console.log('接收到来自iframe的消息:', message)
// 在这里根据消息类型进行相应的处理
}
})
}
}
</script>
# 使用 Echarts 图表
<div class="footerCard-echarts">
<div ref="towChart" style="width: 100%; height: 100%"></div>
</div>
<script lang="ts">
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
export default {
setup() {
const towChart = ref(null)
const initTowChart = () => {
// 初始化 ECharts 实例
const myChart = echarts.init(towChart?.value)
const option = { ...}
// 使用配置项和数据显示图表
myChart.setOption(option)
}
onMounted(() => {
initTowChart()
})
return {
towChart
}
}
}
</script>
# el-menu的使用
<template>
<div class="touchadmin">
<div class="left">
<el-menu class="el-menu-vertical-demo" :default-openeds="[menuList.openeds]"
:default-active="menuList.value"
style="height: 100%; width: 100%"
:unique-opened="true">
<el-sub-menu :index="items.id+''" v-for="(items, indexs) in menuList.list" :key="indexs">
<template #title>
<el-icon>
<CaretRight />
</el-icon>
<span>{{ items.name }}</span>
</template>
<el-menu-item-group v-for="(item, index) in items.children" :key="index">
<el-menu-item @click="handleMenuSelect(item)" :index="item.id+''">
<template #title>
<el-icon :size="16" v-if="item.name===menuList.title">
<StarFilled />
</el-icon>
<el-icon :size="14" v-else>
<Star />
</el-icon>
<span>{{ $t(item.name) }}</span>
</template>
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</div>
<div class="right">
<div class="curpotion">
当前位置:<span style="color: #2968e8">{{ menuList.title }}</span>
</div>
<component :is="menuList.curCom" :cityCode="props.cityCode"/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useRoutesList } from '../../../stores/routesList';
const routes = useRoutesList();
const { routesList } = storeToRefs(routes);
const props = defineProps({
cityCode: {
type: String,
default: '371300',
},
});
interface MenuList {
list: any[];
value: string | null;
openeds: string | null;
title: string;
curCom: any;
}
let menuList = reactive<MenuList>({
list: [],
value: null,
openeds: null,
title: '',
curCom: null,
});
const handleMenuSelect = (item:any) => {
menuList.title = item.name;
const path = `${item.path.replace('/admin/','./')}.vue`;
// /* @vite-ignore */ 忽略vite的警告
menuList.curCom = markRaw(defineAsyncComponent(() => import(/* @vite-ignore */ path)));
};
const setFilterRoutes = () => {
let data = handleSelect(routesList.value);
menuList.list = data.filter((a:any)=> a.name != '默认首页');
menuList.openeds = menuList.list[0]?.id;
if (menuList.list[0] && menuList.list[0]?.children && menuList.list[0]?.children[0]) {
menuList.value = menuList.list[0]?.children[0]?.id;
menuList.title = menuList.list[0]?.children[0]?.name;
const path = `${menuList.list[0]?.children[0]?.path.replace('/admin/','./')}.vue`;
// /* @vite-ignore */ 忽略vite的警告
menuList.curCom = markRaw(defineAsyncComponent(() => import(/* @vite-ignore */ path)));
}
};
const handleSelect = (data: any[]) => {
let menuData: (string | never[])[] = [];
data.map((item: { name: string; children: (string | never[])[] }) => {
if (item.name == '父级') {
menuData = item.children;
}
});
return menuData;
};
onMounted(() => {
setFilterRoutes();
});
</script>
<style lang="scss" scoped>
</style>
# The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0
最终解决方案:在vite.config.ts中添加配置
export default defineConfig({
plugins: [vue()],
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['legacy-js-api']
}
}
}
})
← 语法使用