# 点击时获取事件对象

<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']
      }
    }
  }
})