vue3.x+vite的筆記

下載腳手架(根據(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)行展開


image.png
  • 3、readonly

    • 可以將ref,reactive等進(jìn)行聲明的響應(yīng)式變量轉(zhuǎn)化為只讀的,不允許用戶進(jìn)行修改,否則會(huì)觸發(fā)警告
    • 是深層次的只讀變量
  • 4、isProxy

    • 檢查對(duì)象是否是由 reactivereadonly 創(chuàng)建的 proxy。
  • 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)式的變量
  • 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>
  • 在組件中我們可以直接在模板中使用slots和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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容