下載腳手架(根據(jù)提示進(jìn)行操作)
npm init @vitejs/app
vite內(nèi)部支持less,scss,stylus預(yù)處理,不過需要進(jìn)行本地的下載
npm install -D sass ( less| stylus )
在腳手架中起別名(使用別名后,當(dāng)前方法不會(huì)有提示,對(duì)IDE不友好)
在vite.config.js配置文件中進(jìn)行操作
-
使用絕對(duì)路徑
image.png
image.png 在頁面中引入組件的時(shí)候,直接使用
import HelloWorld from '@/HelloWorld.vue'
注意:
1、vite中對(duì)于setup可以有兩種寫法,一種是在script標(biāo)簽上進(jìn)行寫setup,但是接收props要用defineProps({msg: String})這種寫法還有emits等,不過不需要進(jìn)行return導(dǎo)出
2、還有就是在script下寫setup,不過需要return導(dǎo)出
使用動(dòng)態(tài)的組件進(jìn)行切換
- 首先在當(dāng)前的父組件中引入子組件,并進(jìn)行注冊(cè)
- 使用component標(biāo)簽進(jìn)行展示,使用:is進(jìn)行組件的切換
- 動(dòng)態(tài)組件之間的傳值,我們可以使用computed計(jì)算屬性加v-bind進(jìn)行傳遞
當(dāng)前的父組件
<script >
import HelloWorld from '@/HelloWorld.vue'
import test from '@/test.vue'
import { computed, readonly, ref } from "@vue/reactivity"
export default {
components:{
HelloWorld,test
},
setup(){
const list = readonly(['HelloWorld','test']);
let com = ref(null);
//默認(rèn)顯示helloworld組件
com.value = list[0];
//點(diǎn)擊按鈕進(jìn)行動(dòng)態(tài)的切換組件
const q = (k)=>{
com.value = list[k];
console.log(com.value);
}
//組件之間進(jìn)行動(dòng)態(tài)的傳遞參數(shù)
const _props = computed(()=>{
if(com.value==='HelloWorld'){
return {
msg:'我是hellowrod組件的傳值'
}
}else{
return {
name:'我是測(cè)試組件中的傳值數(shù)據(jù)'
}
}
})
return{
com, q, _props
}
}
}
</script>
<template>
<div class="app">
<header>
<!-- 失活的組件將會(huì)被緩存!-->
<keep-alive>
<component :is="com" v-bind="_props"></component>
</keep-alive>
</header>
<footer>
<button @click="q('0')" >hello</button>
<button @click="q('1')">test</button>
</footer>
</div>
</template>
<style lang="scss">
html,body,#app{
height: 100%;
}
.app{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: #eee;
header{
flex: 1;
}
footer{
height: 200px;
background: #fff;
}
}
</style>
helloworld組件
<script setup>
import { ref } from 'vue'
defineProps({
msg: String
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
</template>
test組件
<script>
import { testRef } from "../common/ref";
export default {
props:{
name:{
type:String,
default:'我是默認(rèn)的測(cè)試ref組件'
}
},
};
</script>
<template>
<h4>測(cè)試Vue中聲明變量的屬性</h4>
<mark>{{name}}</mark>
</template>
聲明響應(yīng)式的屬性
- 1、ref
- 一般用于聲明基本數(shù)據(jù)類型
- 使用ref聲明的變量,操作時(shí)需要使用.value進(jìn)行
- 使用ref聲明的變量是個(gè)深度的響應(yīng)式數(shù)據(jù)
- 可以進(jìn)行一層的解構(gòu)賦值,不能進(jìn)行深度的解構(gòu),否則數(shù)據(jù)就不是響應(yīng)式的數(shù)據(jù)了(會(huì)導(dǎo)致頁面的視圖不更新)
ref.js文件
import { ref } from "vue";
export function testRef() {
let count = ref(0);
let list = ref({
arg: { c: 1, obj: { _c: 2 } }
});
const testRefBtn = () => {
count.value++;
list.value.arg.c++;
list.value.arg.obj._c++;
};
return {
count,
list,
testRefBtn
};
}
-
在當(dāng)前的頁面中引入ref.js文件進(jìn)行解構(gòu)并導(dǎo)出就可以了
image.png -
2、reactive
- 一般用來聲明引用數(shù)據(jù)的
- 使用reactive聲明的數(shù)據(jù)不能使用解構(gòu)賦值,否則解構(gòu)出的數(shù)據(jù)就不是響應(yīng)式的數(shù)據(jù),可以使用toRefs+擴(kuò)展運(yùn)算符將數(shù)據(jù)在轉(zhuǎn)化為ref,然后再進(jìn)行解構(gòu)(好像還是只能解構(gòu)一層,深層次的解構(gòu)待查資料中)
- 一般在導(dǎo)出的時(shí)候,我們可以使用...擴(kuò)展運(yùn)算符進(jìn)行展開,不過要是用toRefs屬性進(jìn)行包裹
reactivejs
import { reactive } from 'vue'
export function reactiveTest(){
let r_arr = reactive([]);
let r_list = reactive({
r_c:0,
r_arg:{
r_num:1,
r_obj:{
r_count:2
}
}
})
const reactiveBtn = () =>{
r_list.r_c++;
r_arr.push(r_list.r_c);
r_list.r_arg.r_num++;
r_list.r_arg.r_obj.r_count++;
console.log(r_list);
}
return {
r_arr,
r_list,
reactiveBtn
}
}
推薦使用圖片下的第二個(gè)紅框,使用擴(kuò)展運(yùn)算符搭配toRefs進(jìn)行展開

-
3、readonly
- 可以將ref,reactive等進(jìn)行聲明的響應(yīng)式變量轉(zhuǎn)化為只讀的,不允許用戶進(jìn)行修改,否則會(huì)觸發(fā)警告
- 是深層次的只讀變量
-
4、isProxy
-
5、isReactive
- 檢查對(duì)象是否是由reactive創(chuàng)建的響應(yīng)式變量
- 如果是用reactive創(chuàng)建的變量之后又使用readonly進(jìn)行包裹,那么也會(huì)返回true
- 如果使用reactive創(chuàng)建的變量之后又使用toRefs進(jìn)行包裹,那么返回false
- 如果reactive中聲明的對(duì)象屬性是常量,那么返回false,只有聲明的變量中有對(duì)象或者是數(shù)組等引用類型,才會(huì)返回true
let r = reactive([0]);
let _r = readonly(r);
let t = toRefs(r)
console.log('使用reactive+readonly------',isReactive(_r));//todo true
console.log('使用reactive+toRefs------',isReactive(t));//todo false
- 6、isReadonly
- 檢查變量是否由readonly創(chuàng)建的變量
- 由reactive創(chuàng)建在用readonly包裹返回true
- 有ref創(chuàng)建基本/引用類型+readonly包裹返回true
- 直接使用readonly創(chuàng)建基本數(shù)據(jù)類型返回false
- 直接使用readonly創(chuàng)建引用數(shù)據(jù)類型返回true
let r = reactive([0]);
let _r = readonly(r);
let t = readonly(0);
let _t = readonly({num:0});
let f = ref(0)
let tt = readonly(f);
console.log('使用reactive+readonly------',isReadonly(_r));//todo true
console.log('使用readonly基本類型------',isReadonly(t));//todo false
console.log('使用readonly引用類型------',isReadonly(_t));//todo true
console.log('使用readonly+ref------',isReadonly(f));//todo false
console.log('使用readonly+ref------',isReadonly(tt));//todo true
- 7、toRaw
- 就是返回使用reactive或者readonly創(chuàng)建的原始數(shù)據(jù)(不是響應(yīng)式的數(shù)據(jù))
- 不推薦經(jīng)常使用
let init = [0]
let r = reactive(init);
let _to = toRaw(r)
console.log('使用reactive+toRaw------',_to);//todo [0]
console.log('使用reactive+toRaw------',_to===init);//todo true
- 8、markRaw
- 標(biāo)記一個(gè)對(duì)象,使其永遠(yuǎn)不會(huì)轉(zhuǎn)換為 proxy。返回對(duì)象本身。
- 當(dāng)前聲明的對(duì)象是原始值,但是對(duì)象中的屬性是可以在被reactive等轉(zhuǎn)化為響應(yīng)式的對(duì)象的
- 轉(zhuǎn)化后的響應(yīng)式的屬性值不等于原始的屬性值
let foo = markRaw({
num:1
})
let _r = reactive({
num:foo.num
})
const btn = ()=>{
foo.num++;
_r.num++;
console.log('reactive----------',_r);//Proxy {num: 2}
console.log('markRaw----------',foo);//{num: 2, __v_skip: true}
}
- 9、shallowReactive
- 也是聲明響應(yīng)式數(shù)據(jù)的,但是這個(gè)可以說是reactive的一種優(yōu)化
- reactive聲明的數(shù)據(jù)是深度的響應(yīng)式,這個(gè)屬性聲明的響應(yīng)式數(shù)據(jù)是淺度的
- 可以對(duì)reactive中的數(shù)據(jù)進(jìn)行優(yōu)化
- 使用這個(gè)屬性聲明的變量在視圖上也是可以進(jìn)行更新的,但是當(dāng)前變量中的對(duì)象或數(shù)組等引用數(shù)據(jù)類型不會(huì)是proxy對(duì)象(創(chuàng)建一個(gè)響應(yīng)式代理,它跟蹤其自身 property 的響應(yīng)性,但不執(zhí)行嵌套對(duì)象的深層響應(yīng)式轉(zhuǎn)換 (暴露原始值))
const noQiao = shallowReactive({
count2:3,
obj1:{
num:3,
obj2:{
aa:3
}
}
})
console.log(isReactive(noQiao.obj1))//false。
isReactive只檢測(cè)引用的數(shù)據(jù)類型
- 10、shallowReadonly
- 創(chuàng)建一個(gè)proxy對(duì)象,使其自身為可讀屬性(淺度)
- 第一層屬性為只讀,不可進(jìn)行修改,否則報(bào)黃色警告
- 第二層或者多層嵌套,可以進(jìn)行修改
- 當(dāng)修改嵌套中的屬性的時(shí)候,頁面視圖是不會(huì)進(jìn)行更新的
export function TestshallowReadonly(){
let test_readonly = shallowReadonly({
t_n:0,//淺度不可修改
t_arg:{//深度可進(jìn)行修改
t_c:2
}
})
const add3 = ()=>{
test_readonly.t_n++;
test_readonly.t_arg.t_c++
console.log(test_readonly);
}
return{
...toRefs(test_readonly),add3
}
}
-
11、unref
- 如果參數(shù)是一個(gè)
ref,則返回內(nèi)部值,否則返回參數(shù)本身。這是val = isRef(val) ? val.value : val的語法糖函數(shù)。 - 總之都會(huì)返回值,就是返回值的類型不同,一個(gè)是普通變量,一個(gè)是響應(yīng)式的變量
- 如果參數(shù)是一個(gè)
-
12、toRef
- 會(huì)為某個(gè)屬性創(chuàng)建一個(gè)ref響應(yīng)式鏈接的數(shù)據(jù)
- 有兩個(gè)屬性,一個(gè)是當(dāng)前的值,必須是對(duì)象,第二個(gè)是對(duì)象中的key
- 可以為reactive數(shù)據(jù)中的某個(gè)屬性,單獨(dú)的在創(chuàng)建一個(gè)ref響應(yīng)式的,也可以讓props中的屬性為單一的響應(yīng)式數(shù)據(jù)
- 不能將reactive中的數(shù)據(jù)解構(gòu)后在使用toRef,會(huì)找不到數(shù)據(jù)
export function testToRef(){
let reactive_list = reactive({
re_foo:1,
re_arg:{
re_c:2
},
re_num:3
})
let toref_foo = toRef(reactive_list,'re_foo');
const add_toref = () =>{
reactive_list.re_foo++;
reactive_list.re_arg.re_c++;
由于reactive是響應(yīng)式的,轉(zhuǎn)化為ref也是響應(yīng)式的,所以當(dāng)reactive聲明的屬性進(jìn)行加的時(shí)候,ref中聲明的屬性是會(huì)跟著變得
console.log('-reactive_list-----------',reactive_list);
console.log('-----toref_foo----------',toref_foo.value);
}
return{
...toRefs(reactive_list),
toref_foo,
add_toref
}
}
-
13、toRefs
- 是為當(dāng)前對(duì)象中的每個(gè)屬性創(chuàng)建一個(gè)ref響應(yīng)式的鏈接
- 一般使其包裹reactive聲明的變量,這樣解構(gòu)的時(shí)候,就不會(huì)將數(shù)據(jù)的響應(yīng)式丟失
-
14、isRef
- 檢查當(dāng)前的變量是否是ref聲明的變量
- 是的話,直接返回true,不是的話,false
- 跟isReactive不同,ref聲明的不管是引用類型,還是基本類型都是可以進(jìn)行檢查的
-
15、customRef
- 可以自定義的創(chuàng)建ref響應(yīng)式的數(shù)據(jù)
- 必須是一個(gè)工廠函數(shù)
- 有兩個(gè)參數(shù)track,trigger,返回的參數(shù)要有g(shù)et,set對(duì)象
// 自定義ref響應(yīng)式數(shù)據(jù)
export function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track();
console.log(track());
console.log(value);
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default {
setup() {
return {
searchVal : useDebouncedRef(0)
}
}
}
<input type="text" v-model="searchVal"/>
- 16、computed 計(jì)算屬性
- 返回一個(gè)不可進(jìn)行修改的ref響應(yīng)式數(shù)據(jù)
const count = ref(1)
const plusOne = computed(() => count.value + 1)
const plusTwo = reactive({
num: count.value*2
})
const plusThree = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1 //這是設(shè)置的時(shí)候,value-1
console.log(count.value) // 0
- 17、watchEffect
- 這是初始化頁面的時(shí)候就會(huì)進(jìn)行監(jiān)聽
- 有兩個(gè)屬性,操作的時(shí)機(jī)不同flush: 'post'/'async'
- 也可以直接使用watchPostEffect,watchSyncEffect這兩個(gè)函數(shù),是上面的別名(刷新的時(shí)機(jī)不同,詳情百度或者看)
官方文檔介紹 - 頁面卸載的時(shí)候會(huì)自動(dòng)進(jìn)行停止監(jiān)聽,也可以返回一個(gè)函數(shù)進(jìn)行手動(dòng)停止監(jiān)聽
const count = ref(0);
watchEffect(() => {
console.log(count.value);----0,----1
})
setTimeout(() => {
count.value++;------1
}, 200);
const stop = watchEffect(() => {
/* ... */
})
// later
stop()---------可以將這個(gè)停止監(jiān)聽的事件放到點(diǎn)擊事件中
- 18、watch
- 跟watchEffect相比較,他是惰性的
- 監(jiān)聽reactive聲明的變量,使用函數(shù)返回的方式
- 監(jiān)聽ref聲明的變量,直接寫就可以
- 可以監(jiān)聽多種方式,使用數(shù)組進(jìn)行包裹就可以
export function testWatch(){
let test_reactive = reactive({
state:0
})
let test_ref = ref(1);
const add_ref = () =>{
test_ref.value++
}
const add_reactive = ()=>{
test_reactive.state++
}
watch(test_ref,(newValue,oldValue)=>{
console.log('---------ref----新---',newValue)
console.log('---------ref----舊---',oldValue)
})
watch(()=>test_reactive.state,(newV,oldV)=>{
console.log('---------reactive----新---',newV)
console.log('---------reactive----舊---',oldV)
})
watch([test_ref,()=>test_reactive.state],([newV,newV1],[oldV,oldV1])=>{
console.log('----------test_ref----新',newV);
console.log('----------test_reactive----新',newV1);
console.log('----------test_ref----舊',oldV);
console.log('----------test_reactive----舊',oldV1);
})
return{
test_ref,
...toRefs(test_reactive),
add_ref,
add_reactive
}
}
- 19、expose
- 如果父組件不通過emit事件進(jìn)行修改子組件中的數(shù)據(jù),而是直接調(diào)用子組件中的其他的方法,通過ref是拿不到的
- 需要通過expose將方法暴露出去,父組件才可以通過ref進(jìn)行取到數(shù)據(jù)
// expose 只能被調(diào)用一次。
// 如果需要暴露多個(gè) property,則它們
// 必須全部包含在傳遞給 expose 的對(duì)象中。
expose({
//將要暴露出去的方法
})
- 20、在script標(biāo)簽上使用setup
- 我們引入的import方法,組件等會(huì)被自動(dòng)解包,直接在模板中使用就可以了
- 要是接收props使用
defineProps接收,emit使用defineEmits,expose使用defineExpose
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
// setup code
</script>
- 在組件中我們可以直接在模板中使用
attrs,要是在js中使用通過
useSlots,useAttrs
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>
可以跟普通的script標(biāo)簽一起搭配使用
-
21、全局組件
- 新建一個(gè)all.vue文件,在main.js中引入,注冊(cè),在需要引入的地方直接寫就可以了
-
在vite中可能會(huì)有緩存,需要修改引入全局組件的父組件,全局組件才會(huì)進(jìn)行顯示
image.png
-
22、使用defineProps 和 defineEmits接收和傳遞
- 在父組件中正常的使用v-bind:屬性值,或@自定義事件名
- 在子組件中使用script setup這種寫法進(jìn)行接收參數(shù)和調(diào)用
父組件
<script>
export default {
setup() {
const btn = (val) =>{
val.value++;
}
return{
btn
}
}
}
</script>
<template>
<div>
<h4>測(cè)試組件,傳值</h4>
<all-h4 :num="4" @btn = "btn"></all-h4>
</div>
</template>
子組件
<script setup>
import { ref } from "vue"
defineProps({
num:Number
})
const count = ref(0);
const emit = defineEmits(['btn'])
const btnCount = ()=>{
emit('btn',count);
}
</script>
<template>
<div>
<h4>我是全局的測(cè)試組件之{{num}}</h4>
{{count}}
<button @click="btnCount">點(diǎn)擊</button>
</div>
</template>
- 23、 defineExpose
- 將當(dāng)前的子組件中的方法,屬性,暴露給父組件
- 在父組件中只能在onMounted生命周期中獲取,其他的地方或者生命周期獲取不到
子組件
<script setup>
import { ref } from "vue"
const count = ref(0);
const allText =() =>{
return '我是全局組件中的方法,但是我不是點(diǎn)擊事件';
}
defineExpose({
count,allText
})
</script>
父組件
<script>
import { ref, onMounted } from "vue"
import all from "/@/all.vue"
export default {
components:{
all
},
setup() {
let q = ref(null);
onMounted(() => {
console.log(q.value.count);
console.log(q.value.allText());
})
return{
btn, q
}
}
}
</script>
<template>
<div>
<h4>測(cè)試組件,傳值</h4>
<all ref="q"></all>
</div>
</template>
-
24、directive(全局)或directives(局部)自定義指令
- 具體可以查看
文檔
- 具體可以查看
main.js中全局的自定義指令
const app = createApp(App)
// app.component('all-h4', all)
app.directive('format',{
mounted(el,binding){
console.log(el);
console.log(binding);
el.innerText = Number(binding.value).toFixed(2);
}
})
app.mount('#app')
- 在組件中使用自定義指令
<mark v-format="20.3242342"></mark>
vite中env進(jìn)行生產(chǎn)測(cè)試環(huán)境變量的切換
- 1、在當(dāng)前的項(xiàng)目根目錄下創(chuàng)建文件.env.['模式']
- 2、.env 這個(gè)文件是在測(cè)試、生產(chǎn)環(huán)境中都是可以獲取到的,可以進(jìn)行公共的路徑進(jìn)行提取
- 3、.env.development 這是測(cè)試環(huán)境中,我們的請(qǐng)求接口路徑
- 4、.env.production 這是生產(chǎn)環(huán)境的
- 5、.env.local或者是.ent.development/production.local 是提交到git上可以進(jìn)行忽略不上傳
- 6、在環(huán)境變量的文件中要是用VITE_進(jìn)行開頭,否則變量在全局是不會(huì)進(jìn)行暴露,獲取不到的
# 本地環(huán)境
ENV = 'development / production' 線上和測(cè)試這個(gè)要進(jìn)行指定,env公共的就不需要了
# 本地環(huán)境接口地址
VITE_API_URL = '2222' 這個(gè)是請(qǐng)求的數(shù)據(jù)接口路徑
在js文件中使用import.meta.env.VITE_API_URL【這個(gè)是自己定義的變量】這種方式進(jìn)行獲取就可以了
vite中進(jìn)行配置axios
- 下載axios
npm i axios -S-D
- 新建一個(gè)request.js文件進(jìn)行簡(jiǎn)單的配置搭配element-plus
import axios from 'axios';
import { ElLoading, ElMessage } from 'element-plus';
const instance = axios.create({
baseURL: import.meta.env.VITE_API_URL,
timeout: 1000,
headers: { 'X-Custom-Header': 'foobar' },
});
let loading;
// 正在請(qǐng)求的數(shù)量
let requestCount = 0;
// 顯示loading
const showLoading = () => {
if (requestCount === 0 && !loading) {
loading = ElLoading.service({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)',
});
}
requestCount++;
};
// 隱藏loading
const hideLoading = () => {
requestCount--;
if (requestCount === 0) {
loading.close();
}
};
// 請(qǐng)求攔截器
instance.interceptors.request.use(
(config) => {
const reqConfig = config;
// showLoading()
// 每次發(fā)送請(qǐng)求之前判斷是否存在token,如果存在,則統(tǒng)一在http請(qǐng)求的header都加上token,不用每次請(qǐng)求都手動(dòng)添加了
// const token = window.localStorage.getItem('token')
// if (token) {
// reqConfig.headers.Authorization = token
// }
// 若請(qǐng)求方式為post,則將data參數(shù)轉(zhuǎn)為JSON字符串
// if (reqConfig.method.toLocaleUpperCase() === 'POST') {
// reqConfig.data = JSON.stringify(reqConfig.data)
// }
return reqConfig;
},
(error) =>
// 對(duì)請(qǐng)求錯(cuò)誤做些什么
Promise.reject(error)
);
// 響應(yīng)攔截器
instance.interceptors.response.use(
(response) => {
// hideLoading()
// 響應(yīng)成功
return response.data;
},
(error) => {
// 響應(yīng)錯(cuò)誤
if (error.response && error.response.status) {
const { status } = error.response;
let message = '';
const actions = {
400: '請(qǐng)求錯(cuò)誤',
401: '請(qǐng)求錯(cuò)誤',
404: '請(qǐng)求地址出錯(cuò)',
408: '請(qǐng)求超時(shí)',
500: '服務(wù)器內(nèi)部錯(cuò)誤!',
501: '服務(wù)未實(shí)現(xiàn)!',
502: '網(wǎng)關(guān)錯(cuò)誤!',
503: '服務(wù)不可用!',
504: '網(wǎng)關(guān)超時(shí)!',
505: 'HTTP版本不受支持',
20000: '請(qǐng)求失敗',
};
message = actions[status] ? actions[status] : actions['20000'];
ElMessage.error(message);
return Promise.reject(error);
}
return Promise.reject(error);
}
);
const request = (url, method, data = {}, isloading = false) => {
!isloading && showLoading(); //todo 也可以放到請(qǐng)求攔截的里面中,這里更方便的進(jìn)行控制
return new Promise((resolve, reject) => {
instance({
method: method,
url: url,
data: data,
})
.then((res) => {
console.log('成功-------', res);
resolve(res);
})
.catch((msg) => {
console.log('失敗-------', msg);
ElMessage.error(msg);
reject(msg);
})
.finally(() => {
!isloading && hideLoading(); //todo 這個(gè)可以放到響應(yīng)攔截器中,這里進(jìn)行方便的控制
});
});
};
export default request;
vite配置mock,進(jìn)行模擬請(qǐng)求
- 首先下載mockjs
npm i mockjs vite-plugin-mock cross-env -D
- 在vite.config.js中進(jìn)行配置
import { defineConfig } from 'vite';
import { resolve } from 'path';
import vue from '@vitejs/plugin-vue';
import { viteMockServe } from 'vite-plugin-mock'; 這里進(jìn)行引入
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import ElementPlus from 'unplugin-element-plus/vite';
// https://vitejs.dev/config/
export default defineConfig({
// 公共路徑測(cè)試是絕對(duì)路徑,生產(chǎn)是相對(duì)路徑
base: process.env.NODE_ENV === 'production' ? process.env.VITE_PUBLIC_PATH : './',
plugins: [
vue(),
ElementPlus({
//elementui的樣式插件
importStyle: 'sass',
useSource: true,
}),
Components({
//elementui 組件的自動(dòng)導(dǎo)入插件
resolvers: [ElementPlusResolver()],
}),
//todo 配置mockjs模擬請(qǐng)求數(shù)據(jù)的
viteMockServe({ supportTs: false }), 這里配置mockjs
],
resolve: {
//todo 配置別名
alias: {
'/@': resolve(__dirname, './src/components'),
},
},
server: {
proxy: {配置跨域
//代理(解決跨域問題)
'/api': {
target: 'http://localhost:3000/',
ws: true,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
// build: {
// outDir: 'dist',
// minify: 'esbuild',
// sourcemap: false,//打包后不生成sourcemap文件
// chunkSizeWarningLimit: 1500,
// },
});
- 要是項(xiàng)目中有.env.development文件,將里面的默認(rèn)路徑跟vite.config.js中的配置跨域的路徑保持一致
- 最后在項(xiàng)目的根目錄下創(chuàng)建一個(gè)mock的文件夾,新建一個(gè)index.js文件進(jìn)行模擬接口數(shù)據(jù)
export default [數(shù)組的形式,可以寫多個(gè)對(duì)象形式的接口,也可以只返回一個(gè)對(duì)象
{
url: '/api/get',
method: 'get',
response: () => {
return {
code: 0,
data: {
name: 'vben',
},
}
},
},
]
- 在src文件下,新建一個(gè)api文件夾,在新建一個(gè)test.js專門將接口進(jìn)行統(tǒng)一管理
import request from './request';
export const test = () => {
return request('/api/get', 'get');
};
- 隨便在一個(gè).vue文件中進(jìn)行請(qǐng)求調(diào)用
import { test } from '../api/test.js'
setup(){
onMounted(()=>{
這是使用axios進(jìn)行封裝的調(diào)用接口
test().then(data => console.log(data)).catch(msg => console.log(msg))
這是直接使用內(nèi)置的fetch進(jìn)行接口的調(diào)用請(qǐng)求
fetch('/api/get').then(res => res.json()).then(m => console.log(m)).catch(a => {
console.log(a);
})
})
}
vite中進(jìn)行簡(jiǎn)單的配置eslint+prettierrc(目前配置的不是很準(zhǔn)確,后面會(huì)進(jìn)行深入的)
npm install --save-dev eslint eslint-plugin-vue 這個(gè)是沒有加ts的eslint,下面的配置是加了ts的eslint,到時(shí)候報(bào)錯(cuò)的話可以進(jìn)行下載下或者將下面的配置文件中的ts的eslint進(jìn)行刪除就可以了
- 在根目錄下新建一個(gè).eslintrc.js文件然后就可以進(jìn)行簡(jiǎn)單的一些提示
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
extends: ['plugin:vue/vue3-essential', 'plugin:vue/essential', 'eslint:recommended'],
plugins: ['vue', '@typescript-eslint'],
rules: {
// http://eslint.cn/docs/rules/
// https://eslint.vuejs.org/rules/
'@type-eslint/ban-ts-ignore': 'off',
'@type-eslint/explicit-function-return-type': 'off',
'@type-eslint/no-explicit-any': 'off',
'@type-eslint/no-var-requires': 'off',
'@type-eslint/no-empty-function': 'off',
'@type-eslint/no-use-before-define': 'off',
'@type-eslint/ban-ts-comment': 'off',
'@type-eslint/ban-types': 'off',
'@type-eslint/no-non-null-assertion': 'off',
'@type-eslint/explicit-module-boundary-types': 'off',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/html-self-closing': 'off',
'vue/no-multiple-template-root': 'off',
'vue/require-default-prop': 'off',
'vue/no-v-model-argument': 'off',
'vue/no-arrow-functions-in-watch': 'off',
'vue/no-template-key': 'off',
'vue/no-v-html': 'off',
'vue/comment-directive': 'off',
'vue/no-parsing-error': 'off',
'vue/no-deprecated-v-on-native-modifier': 'off',
'no-useless-escape': 'off',
'no-sparse-arrays': 'off',
'no-prototype-builtins': 'off', //禁止直接調(diào)用 Object.prototypes 的內(nèi)置屬性off關(guān)閉
'no-constant-condition': 'off', //禁止在條件中使用常量表達(dá)式
'no-use-before-define': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'generator-star-spacing': 'off',
'no-unreachable': 'off',
'no-multiple-template-root': 'off',
'no-unused-vars': 'error',
'no-v-model-argument': 'off',
'no-case-declarations': 'off',
'no-undef': 'off',
'no-var': 'error', //禁止使用變量var進(jìn)行聲明,修復(fù)為let,const
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
//強(qiáng)制使用單引號(hào)
quotes: ['error', 'single'],
//強(qiáng)制不使用分號(hào)結(jié)尾
semi: ['error', 'never'],
},
};
- 在package.json文件中的script中進(jìn)行配置一個(gè)指令
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
- 每次進(jìn)行輸入指令npm run lint-fix 就會(huì)檢查出我們項(xiàng)目中的src目錄下的所有文件的語法是否錯(cuò)誤,一些簡(jiǎn)單會(huì)自動(dòng)的幫我們進(jìn)行修復(fù)
- 根目錄下有個(gè).vscode文件夾,在新建一個(gè)settings.json(prettierrc這個(gè)文件中的配置可能不起作用,只好在這個(gè)文件中進(jìn)行配置了)
{
"eslint.alwaysShowStatus": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
//保存自動(dòng)格式化
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.workingDirectories": [{ "mode": "auto" }],
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"],
//根據(jù)文件后綴名定義vue文件類型
"files.associations": {
"*.vue": "vue"
},
//開啟 eslint 支持
"prettier.eslintIntegration": true,
//使用單引號(hào)
"prettier.singleQuote": false,
//結(jié)尾不加分號(hào)
"prettier.semi": true
}
- 在項(xiàng)目的根目錄下新建一個(gè).prettierrc.js文件
module.exports = {
// 一行最多多少個(gè)字符
printWidth: 150,
// 指定每個(gè)縮進(jìn)級(jí)別的空格數(shù)
tabWidth: 2,
// 使用制表符而不是空格縮進(jìn)行
useTabs: true,
// 在語句末尾打印分號(hào)
semi: true,
// 使用單引號(hào)而不是雙引號(hào)
singleQuote: true,
// 更改引用對(duì)象屬性的時(shí)間 可選值"<as-needed|consistent|preserve>"
quoteProps: "as-needed",
// 在JSX中使用單引號(hào)而不是雙引號(hào)
jsxSingleQuote: false,
// 多行時(shí)盡可能打印尾隨逗號(hào)。(例如,單行數(shù)組永遠(yuǎn)不會(huì)出現(xiàn)逗號(hào)結(jié)尾。) 可選值"<none|es5|all>",默認(rèn)none
trailingComma: "es5",
// 在對(duì)象文字中的括號(hào)之間打印空格
bracketSpacing: true,
// jsx 標(biāo)簽的反尖括號(hào)需要換行
jsxBracketSameLine: false,
// 在單獨(dú)的箭頭函數(shù)參數(shù)周圍包括括號(hào) always:(x) => x \ avoid:x => x
arrowParens: "always",
// 這兩個(gè)選項(xiàng)可用于格式化以給定字符偏移量(分別包括和不包括)開始和結(jié)束的代碼
rangeStart: 0,
rangeEnd: Infinity,
// 指定要使用的解析器,不需要寫文件開頭的 @prettier
requirePragma: false,
// 不需要自動(dòng)在文件開頭插入 @prettier
insertPragma: false,
// 使用默認(rèn)的折行標(biāo)準(zhǔn) always\never\preserve
proseWrap: "preserve",
// 指定HTML文件的全局空格敏感度 css\strict\ignore
htmlWhitespaceSensitivity: "css",
// Vue文件腳本和樣式標(biāo)簽縮進(jìn)
vueIndentScriptAndStyle: false,
// 換行符使用 lf 結(jié)尾是 可選值"<auto|lf|crlf|cr>"
endOfLine: "lf",
}
vite配置postcss
- 這個(gè)插件有很多的功能,具體可以在GitHub上查看下,這里簡(jiǎn)單的介紹下幾個(gè)
- 可以參考這篇文章http://www.itdecent.cn/p/21be605c6ad1
- vite中是內(nèi)置支持postcss的,只需要我們將插件進(jìn)行引入在vite.config.js中進(jìn)行配置就可以使用了
- autoprefixer這個(gè)插件是當(dāng)我們使用新的css時(shí),為了兼容老的瀏覽器,會(huì)自動(dòng)將我們的代碼加個(gè)前綴
npm install autoprefixer -D
- 在vite.config.js中進(jìn)行配置
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import autoprefixer from "autoprefixer"http://引入插件
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
css: {
postcss: {
plugins: [autoprefixer],//進(jìn)行注冊(cè)
},
},
})
-
還需要進(jìn)行兼容瀏覽器的版本,不可能是全部瀏覽器的版本都可以進(jìn)行添加,那就太多了,需要有個(gè)限制進(jìn)行約束在package.json中
image.png - 或者在根目錄下新建.browserslistrc文件,不用逗號(hào),換行就行
> 1%
last 2 versions
- 具體可以參考這篇文章http://www.itdecent.cn/writer#/notebooks/49948771/notes/86532182/preview
- 然后當(dāng)我們的項(xiàng)目打包后,就會(huì)將display:flex;加上一些前綴




