vite+typescript从入门到实战(二):https://developer.aliyun.com/article/1483572
vite中安装sass 预处理器
npm install --save-dev sass
三、关于sass的“.....Using / for division.....”报错
这是由于sass版本导致的问题,不影响项目编译,解决方法:
1.将 “/”的位置改为 match.dev(arg1,arg2)
@use "sass:math"; /* 头部不要忘记加入这个,不然会报错找不到math */ /* 将这个 */ @return ($px/$rem)+rem; /* 改为下边这个 */ @return match.div($px,$rem)+rem;
2.使用官方sass-migrator工具
$ npm install -g sass-migrator
环境变量文件
.env
# port 端口号 VITE_PORT = 8888 # open 运行 npm run dev 时自动打开浏览器 VITE_OPEN = false # public path 配置线上环境路径(打包)、本地通过 http-server 访问时,请置空即可 VITE_PUBLIC_PATH = /vue-next-admin-preview/
.env.development
# 本地环境 ENV = 'development' # 本地环境接口地址 VITE_API_URL = 'http://localhost:8888/'
.env.production
# 线上环境 ENV = 'production' # 线上环境接口地址 VITE_API_URL = 'https://lyt-top.gitee.io/vue-next-admin-preview/'
组件传值
父传子
父组件:
<template> <div class="son"> <son1 :toChild="toChild" /> </div> </template> <script> import { reactive, toRefs } from 'vue' import son1 from './branch/son1.vue' export default { components: { son1 }, setup(props,context) { const data = reactive({ toChild: '传递数据1' }) return { ...toRefs(data) } } } </script>
子组件
// 第一种-------------------配置setup------------------- <script> export default { props: { //这里必须写,不然setup中的props也拿不到 toChild: { type: String, default: '无数据' } }, setup(props, context) { console.log(props.toChild) // 传递数据1 return {}; }, }; </script> // 第二种------------------setup语法糖-------------------- <script setup> const props = defineProps({ name: { type: String, default: '' } }) </script>
注意:defineProps只能直接暴露在setup下,不能放在回调中。不需要引入,直接调用即可
子传父
子组件
// 第一种-----------------配置setup--------------------- <script> import { ref } from "vue"; export default { setup(props, context) { const { emit } = context const msg = ref('999') // 子传父 const send = () => { emit('sonSend',msg) } return { msg, send }; }, }; </script> // 第二种-----------------setup语法糖---------------------- <script setup> const emit = defineEmits(['sonSend']) const btnClick = () => { emit('sonSend', '999') } </script>
注意:defineEmits只能直接暴露在setup下,不能放在回调中。不需要引入,直接调用即可.同defineProps
父组件
<template> <div class="son"> <son1 @sonSend="sonSend" /> //监听子组件的自定义事件 </div> </template> <script> import son1 from './branch/son1.vue' export default { components: { son1 }, setup(props,context) { const sonSend = (val) => { console.log(val.value) // 999 } return { sonSend } } } </script>
兄弟之间传值
vue2 我们通过EventBus new Vue的方式来实现。Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus
1.安装mitt
npm install mitt --save
- 新建 bus.js
//bus.js import mitt from 'mitt' const bus = mitt() export default bus
然后直接引用就可以了
兄弟组件1
<template> <button @click="btn">我是兄弟组件b</button> </template> import bus from '@/utils/bus' function btn() { bus.emit("fromBother", '传给好兄弟'); //参数一为自定义事件名称,参数二是传递的参数 } return{ btn }
兄弟组件2
import bus from '@/utils/bus' import { onUnmounted } from "vue" setup(props,context) { function fromBother(val) { console.log(val,'val--->>>兄弟传过来') } onMounted(() => { bus.on('fromBother',fromBother) //监听兄弟组件传过来的值 }) onUnmounted(() => { //销毁的时候 解绑 bus.off('fromBother',fromBother) }) return {} }
封装request.ts
import axios from 'axios'; import { ElMessage, ElMessageBox } from 'element-plus'; import { Session } from '/@/utils/storage'; // 配置新建一个 axios 实例 const service = axios.create({ baseURL: import.meta.env.VITE_API_URL as any, timeout: 50000, headers: { 'Content-Type': 'application/json' }, }); // 添加请求拦截器 service.interceptors.request.use( (config) => { // 在发送请求之前做些什么 token if (Session.get('token')) { config.headers.common['Authorization'] = `${Session.get('token')}`; } return config; }, (error) => { // 对请求错误做些什么 return Promise.reject(error); } ); // 添加响应拦截器 service.interceptors.response.use( (response) => { // 对响应数据做点什么 const res = response.data; if (res.code && res.code !== 0) { // `token` 过期或者账号已在别处登录 if (res.code === 401 || res.code === 4001) { Session.clear(); // 清除浏览器全部临时缓存 window.location.href = '/'; // 去登录页 ElMessageBox.alert('你已被登出,请重新登录', '提示', {}) .then(() => {}) .catch(() => {}); } return Promise.reject(service.interceptors.response); } else { return response.data; } }, (error) => { // 对响应错误做点什么 if (error.message.indexOf('timeout') != -1) { ElMessage.error('网络超时'); } else if (error.message == 'Network Error') { ElMessage.error('网络连接错误'); } else { if (error.response.data) ElMessage.error(error.response.statusText); else ElMessage.error('接口路径找不到'); } return Promise.reject(error); } ); // 导出 axios 实例 export default service;
使用request.ts
import request from '/@/utils/request'; /** * 用户登录 * @param params 要传的参数值 * @returns 返回接口数据 */ export const signIn = (params: object): Object => request({ url: '/user/signIn', method: 'post', data: params })
getCurrentInstance 方法
1、概述:一个很重要的方法,获取当前组件的实例、上下文来操作router和vuex等。
2、使用:由vue提供,按需引入:import { getCurrentInstance} from 'vue';
import { getCurrentInstance } from 'vue'; // 获取当前组件实例 const instance = getCurrentInstance(); // 获取当前组件的上下文,下面两种方式都能获取到组件的上下文。 const { ctx } = getCurrentInstance(); // 方式一,这种方式只能在开发环境下使用,生产环境下的ctx将访问不到 const { proxy } = getCurrentInstance(); // 方式二,此方法在开发环境以及生产环境下都能放到组件上下文对象(推荐) // ctx 中包含了组件中由ref和reactive创建的响应式数据对象,以及以下对象及方法; proxy.$attrs proxy.$data proxy.$el proxy.$emit proxy.$forceUpdate proxy.$nextTick proxy.$options proxy.$parent proxy.$props proxy.$refs proxy.$root proxy.$slots proxy.$watch
使用 proxy
const { proxy } = getCurrentInstance() as any; proxy.mittBus.emit('restoreDefault'); proxy.mittBus.on('setSendColumnsChildren', (res: any) => { state.menuList = res.children; });
provide和inject
provide和inject,他们的使用时成组合使用,用于从父级组件向下级的子组件,孙组件传递值。
1、概述:实现嵌套组件树形数据传递与接收。
2、使用:由vue提供,按需引入:
import { provide, inject } from 'vue';
import { provide, inject } from 'vue' // 父组件注入 const component = { setup() { provide('name', 'zhagn_san'); // 如果是需要注入多个值则重复使用provide即可 }; }; // 子组件接收 const children = { setup() { // inject的第二个参数为没有接收到注入的数据时的默认返回值,如果没有,则返回undefined const user = inject('name', 'li_si'); // 需要接收多个注入的值也是重复使用inject即可 return { user }; }; };
4、实例:再实际使用过程中,往往我们需要将注入的值实现响应式变化,则需要注入响应式
// 父组件注入 const component = { setup() { const user = reactive({ name: 'zhagn_san', age: 20 }); provide('user', user); }; }; // 子组件接收后,如果父组件中的user发生了改变,则子组件中也会发生响应式变化 const children = { setup() { const user = inject('user', {}); return { user }; }; };
5、注意:不建议在注入时对响应式变量进行改变(在子组件中改变注入的值),因为此操作会改变Vue的单向数据流。建议采用注入改变其值的方法来对响应式变量进行改变。
import { reactive, provide, inject } from 'vue' // 父组件注入 const component = { setup() { const user = reactive({ name: 'zhagn_san', age: 20 }); function changeHandler() { user.age = 30; } provide('user', user); provide('changeHandler', changeHandler); }; }; // 子组件接收后,通过调用注入的方法来对响应式变量进行改变 const children = { setup() { const user = inject('user', {}); const changeHandler = inject('changeHandler'); return { user, changeHandler }; }; };
emits方法
1、概述:当前组件的通过emit的事件列表
2、类型:Array|Object
3、作用:Vue3.0中使用emit发起事件时会要求当前组件记录emit事件(没有则控制台会抛出警告)。
3、用途:用于记录当前组件emit的事件,当为对象时,则可以验证传入的值是否有效。
setup(prop, { emit }) { const changeOne = val => { emit('on-changeOne', val); }; const changeTwo = val => { emit('on-changeTwo', val); }; }
数组用法
export default { emits:['on-changeOne', 'on-changeTwo'], setup() {...} }
对象用法,当emits为对象时,可以验证事件中的参数是否有效
export default { emits:{ click: null, 'on-changeOne': payload => { if(...) { return true; // 验证通过 } console.warn('验证失败!') return false; // 验证失败,控制台打印vue警告及“验证失败!”警告 }, 'on-changeTwo': payload => {...} }, setup() {...} } // 当验证函数中没有返回值return时,默认返回true
emits无论是数组或者对象用法最终都会将事件给传递出去,数组或对象的使用只是为了记录实例中的emit事件,或者是验证事件中的参数。
参考文献
vite2 + Vue3 中 组件传值
https://blog.csdn.net/m0_51431448/article/details/122689619
在vue3中使用mitt,达到evenbus的效果
https://www.cnblogs.com/cn-oldboy/p/15791920.html
vite 安装及创建项目
https://www.jianshu.com/p/3178972c6815
(十四)Vue3.x核心之getCurrentInstance
https://www.jianshu.com/p/5558cadd10b9
Vue3.x中的emits选项
https://www.jianshu.com/p/2c9a08e9a8c1