Vue3 学习笔记

vue3

官网:简介 | Vue.js (vuejs.org)

1. 环境搭建与启动

npm create vue@latest

这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具

之后,你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:

复制代码
✔ Project name: ... <your-project-name> 
✔ Add TypeScript? ... No / Yes
✔ Add JSX Support? ... No / Yes
✔ Add Vue Router for Single Page Application development? ... No / Yes
✔ Add Pinia for state management? ... No / Yes
✔ Add Vitest for Unit testing? ... No / Yes
✔ Add an End-to-End Testing Solution? ... No / Cypress / Playwright
✔ Add ESLint for code quality? ... No / Yes
✔ Add Prettier for code formatting? ... No / Yes

Scaffolding project in ./<your-project-name>...
Done.

注意project name 输入的时候不要有大写字母

然后会提示:

复制代码
Done. Now run:

  cd first_vue (刚刚填写的project名称)
  npm install
  npm run dev

按照要求 进入 first_vue,执行 npm install ,npm run dev

复制代码
  VITE v4.4.9  ready in 494 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

出现以上界面就成功了,在浏览器界面访问 http://localhost:5173/ 可以看到 vue 界面

使用 vscode 进入项目会发现有很多的文件夹

创建好项目了也可以直接在vscode的左下角使用 npm 脚本

下载 volar 插件:


2. 修改端口

vue3 默认端口5173

想要把端口号修改为9090,在vite.config.js中写入

js 复制代码
server: {
    port: 9090,//端口号
    host: true,//ip地址 或 '0.0.0.0' 或 "loaclhost"
    open: false, //启动后是否自动打开浏览器
    https: false, // 是否开启 https
},

3. 组合式API

3.1 setup
  1. 执行时间beforeCreate还要

  2. setup函数中,获取不到 this

  3. setup函数中的 数据 和 函数,需要 return,简化请看第4点

  4. 如果在 script中 使用setup,就不需要return了(语法糖),帮你return了。

vue 复制代码
  <!-- script加上setup允许在script中直接编写组合式 api-->
  <script setup>
  
  const messge = "qwq";
  const hello = "hello vue3"
  const show = () => {
      console.log(messge);
  }
  
  </script>
  
  <template>
      <p> {{ hello }}</p>
      <button @click="show">button</button>
  </template>

3.2 reactive 和 ref 函数

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>

import { reactive } from 'vue'
// 接受对象参数传递并返回一个响应式的对象,响应式理解的来说就是同步变化
const state = reactive({
    count:100
})
// 这里{count:100} 是新建了一个匿名对象作为 reactive 的参数,js中的对象就是 name:value 键值对
const setCount = () => {
    state.count++;
}

</script>

<template>
    <div>
        <div> {{ state.count }} </div>
        <button @click="setCount"> +1 </button>
    </div>
</template>

这里不一样的是 既可以接收简单类型,又可以接收对象类型

本质:在原有传入数据的基础上,外层包了一层对象,实际上还是借助了 reactive

注意:在 script 中访问 ref 定义的数据的时候需要通过.value,但是在template中 不需要

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>

import { ref } from 'vue'
const count = ref(0)
console.log(count.value); 

</script>

<template>
    <div>
        {{ count }} 
    </div>
    <div>
        <button @click="() => { count++ }"> +1 </button>
    </div>
</template>

3.3 computed

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import { computed, ref } from 'vue';

const list = ref([1,1,4,5,1,4])
const computedList = computed(
    () =>{
        return list.value.filter(i => i > 2)
    }
)
const userInput = ref('')

const addValue = (userInput) => {
    if (userInput != '') {
        list.value.push(parseInt(userInput))
    }
}


</script>

<template>
    <div>
        <div>list:{{ list }}</div>
        <div>过滤之后的list:{{ computedList }}</div>
        <div>
          <input v-model="userInput" placeholder="输入一个值" />
          <button @click="addValue(userInput)">添加值到list</button>
        </div>
      </div>
    
</template>

注意:computed中也可以编写 get set方法,可以用来将 ref 对象变为可写 ( ref 对象默认可读)

例如:

vue 复制代码
<script setup>
import { computed, ref } from 'vue';
const tmp = ref(3)
const tmpComputed = computed({
    get:() => {
        return tmp.value + 1
    },
    set:(val) => {
        tmp.value = val
    }
})

tmpComputed.value = 2
console.log(tmp.value)
console.log(tmpComputed.value)

</script>

3.4 watch

作用:侦听一个或者多个数据的变化,数据变化时立即执行回调函数

使用:

  1. 导入 watch 函数
  2. 执行 watch 函数传入要侦听的响应式数据(ref 对象)和 回调函数

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import { watch, computed, ref } from 'vue';

const number = ref(0)
const name = ref("张三")

const changNumber = () => {
    number.value++;
}

const changeName = () => {
    name.value = "李四"
}

// 监视单个 ref对象 ,number
// 注意这里是对象,不需要取值
// 语法为watch( ref对象, (newValue, oldValue) => {})
watch(number, (newValue, oldValue) => {
    console.log(newValue, oldValue);
})

// 监视多个 ref 对象,number 和 name
// 语法为watch([ref对象1,ref对象2...], (newArr, oldArr) => {})
watch([number, name], (newArr, oldArr) => {
    console.log(newArr, oldArr);
})


</script>

<template>
    <div>
        <div>
            {{ number }}
            <button @click="changNumber">change number</button>
        </div>
        <div>
            {{ name }}
            <button @click="changeName">change name</button>
        </div>
    </div>
    
</template>

这里其实 oldValue 和 oldArr,可以忽略,具体情况具体分析,如果不需要旧值,不接收就好了,这也是newValue等是第一个参数的原因

immediate 和 deep :

immediate:

添加immediate对象,可以让监视在程序加载时立即启动一次,而不需要等待第一次值改变。

例如:

js 复制代码
watch(number, (newValue, oldValue) => {
    console.log(newValue, oldValue);
},{
    immediate:true
})

deep:

deep 是深度监视 ,watch的默认监视进行的是浅层监视,对于简单类型的值可以直接监视,但监视不到复杂类型内部数据的变化。

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import { watch, computed, ref } from 'vue';
const person = ref({
    name:"张三",
    age:18,
    sex:1
})

const changeAge = () => {
    person.value.age++;
}

watch(person, (newValue) => {
    console.log(newValue);
},{
    deep:true
})

</script>

<template>
    <div>
        <div>{{ person }}</div>        
        <button @click="changeAge">age++</button>
    </div>
    
</template>

使用deep相当于监视了对象的所有属性,如果我只需要监听一个特定的属性呢?

也可以实现,例如:

js 复制代码
watch(()=>person.value.age, (newValue)=>{
    console.log(newValue);
})

就是把第一个参数从对象,换成了一个返回你需要监听属性的函数


3.5 生命周期

每一个生命周期都有一个对应的方法,进行到该生命周期就会触发这个方法。

例如:

js 复制代码
onMounted(() => {
    console.log("mounted生命周期函数")
})

3.6 父子通信
3.6.1 在父组件中引入子组件:

局部导入:

components包下写子组件,例如sonCom.vue

然后在父组件中 import 导入后,直接在<template>中使用标签使用

例如:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import sonCom from './components/sonCom.vue'
</script>
<template>
    <div>
        <h3> 父组件 </h3>
    </div>
    <div>
        <sonCom></sonCom>
    </div>
</template>
<style>
</style>

3.6.2 父传子:

例如,父组件:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import sonCom from './components/sonCom.vue'
import { ref } from 'vue';

const money = ref(10000)

</script>

<template>
    <div>
        <h3> 父组件 </h3>
    </div>
    <div>
        <sonCom car="兰博基尼" :money="money"></sonCom>
    </div>
    
</template>

<style>

</style>

子组件,sonCom:

vue 复制代码
<script setup>
const props = defineProps({
    car: String,
    money: Number
})
console.log(props.car);  //这里注意脚本中需要写 props.属性,但是模板中不需要写,直接用属性

</script>

<template>
    <div class="son">
        <p>我是子组件</p>
        <p>我是父组件中继承了:{{ car }}, {{ money }}</p>
    </div>

</template>

<style>
.son{
   border: solid 2px brown;
   padding: 30px;
}
</style>

3.6.3 子传父:

如果要修改父组件的值:

  1. 调用我需要做的修改父组件的值的方法
  2. 在方法中调用 emit 函数,语法为 emit('事件名', 参数)
  3. 使用defineEmits方法提供 emit 函数,语法const emit = defineEmits(['事件1', '事件2']),理解成注册事件就行
  4. 父组件在 子组件标签中 用@emit传来的事件名='xxxx',绑定子组件的事件
  5. 定义xxxx,其中可以使用emit传来的参数

例如,父组件:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import sonCom from './components/sonCom.vue'
import { ref } from 'vue'

const money = ref(10000);
const earnMoney = () =>{
    money.value += 50;
}
const useMoney = (restMoney) => {
    money.value = restMoney
}

</script>

<template>
    <div>
        <h3> 父组件 </h3>
        <p>
             当前money:{{ money }}
             <button @click="earnMoney"> 赚钱 </button>
        </p>
        
    </div>
    <div>
        <sonCom car="兰博基尼" :money="money" @useMoney="useMoney"></sonCom>
    </div>
    
</template>

<style>

</style>

子组件:

vue 复制代码
<script setup>
const props = defineProps({
    car: String,
    money: Number
})
const emit = defineEmits(["useMoney"])
const useMoney = () => {
    emit('useMoney', 5)
}


</script>

<template>
    <div class="son">
        <h3>我是子组件</h3>
        <p>
            我是父组件中继承了:{{ car }}, {{ money }}
            <button @click="useMoney"> 花钱 </button>
        </p>
    </div>

</template>

<style>
.son{
   border: solid 2px brown;
   padding: 30px;
   margin-top: 10px;
}
</style>

3.7 模板引用 与 defineExpose

这样也可以实现子传父。


3.8 provide 和 inject 跨层传递

3.8 defineOptions

3.9 defineModel

想要使用首先要在vite中修改:

js 复制代码
plugins: [
    vue({
      script: {
        defineModel: true, // 启用defineModel
      }
    }),
  ],

4. pinia

简介 | Pinia (vuejs.org)

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

安装

npm install pinia

导包:

js 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')
4.1 快速入门

使用:

  1. 在 src 下新建文件夹 store 用来存储仓库
  2. 在 store 下新建仓库 ( js ) 并使用defineStore函数创建对象
  3. 在需要使用仓库的地方 实例化仓库对象,直接调用对象中的值 和 函数

例如:

testStore:

js 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue';
export const useTestStore = defineStore('testStore', () => {
    
    const count = ref(0);

    const subCount = () => {
        count.value--;
    }
    const addCount = () => {
        count.value++;
    }
    

    return{
        count,
        subCount,
        addCount,
    }
})

App.vue:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import sonCom from './components/sonCom.vue';
import sonCom2 from './components/sonCom2.vue';
import { useTestStore } from './store/test';

const testStore = useTestStore() //创建实例

</script>

<template>
    <div>
        <h1>我是父组件 -- {{ testStore.count }}</h1>
        <sonCom></sonCom>
        <sonCom2></sonCom2>
    </div>
</template>

<style>

</style>

sonCom.vue:

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import { useTestStore } from '../store/test';
const testStore = useTestStore()

</script>

<template>
    <div>
        <h2>
            我是儿子组件 -- {{ testStore.count }}
            <button @click="testStore.addCount"> + </button>
        </h2>
    </div>
</template>

<style></style>

4.2 异步请求

我们使用axios来发送异步请求,例如:

js 复制代码
import { defineStore } from "pinia";
import axios from 'axios'
import { ref } from "vue";

export const useaxiosStore = defineStore("axiosStore", () => {

    const channellist = ref([])
    const getList = async() => { //async 表示异步函数 
        const { data: { data } } = await axios.get("http://localhost:8080/pinia") // 等待数据获取完毕
        channellist.value = data.channels
    }

    return{
        channellist,
        getList
    }
})

app.vue

vue 复制代码
<!-- script加上setup允许在script中直接编写组合式 api-->
<script setup>
import { useaxiosStore } from './store/axios';
const axiosStore = useaxiosStore()  //创建实例
</script>
<template>
    <div>
        <button @click="axiosStore.getList"> 获取数据 </button>
        <ul>
            <li  v-for="i in axiosStore.channellist" :key="i.id" > {{ i.name }} </li>
        </ul>

    </div>
</template>
<style>
</style>

java,接收请求并返回数据:

java 复制代码
package com.zhx.controller;


import com.zhx.pojo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.PipedReader;
import java.util.*;

@RestController
public class piniaController {
    @GetMapping("/pinia")
    public Result send(){
        class data{
            private List<Object> channels;
            private String message;

            public data(List<Object> channels, String message) {
                this.channels = channels;
                this.message = message;
            }

            public List<Object> getChannels() {
                return channels;
            }

            public void setChannels(List<Object> channels) {
                this.channels = channels;
            }

            public String getMessage() {
                return message;
            }

            public void setMessage(String message) {
                this.message = message;
            }
        }

        List<Object> list = new ArrayList<>();
        for(int i=1;i<=5;i++){
            Map<String, Object> map = new HashMap<>();
            map.put("id", i);
            map.put("name", "name:"+i);
            list.add(map);
        }
        return Result.success(new data(list, "qwq"));
    }
}

这里还需要解决一下跨域请求,使用 java 的 config类:

java 复制代码
package com.zhx.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();

        // 允许哪些源访问
        config.addAllowedOrigin("http://localhost:5173");

        // 允许哪些 HTTP 方法
        config.addAllowedMethod("GET");

        source.registerCorsConfiguration("/pinia/**", config);
        return new CorsFilter(source);
    }
}

4.3 仓库解构,storeToRefs(store)

我们之前都是直接导入仓库,然后实例化,然后使用 .进行访问,如果想要直接进行解构的话,需要注意两点:

  1. 解构 store 的状态需要使用storeToRefs(store)
  2. 解构 store 的 action(组合式中就是函数 )直接解构

因为解构会破坏响应性,但是 action ,比如说函数没有响应性可言,就是用就完事了。

例如:

vue 复制代码
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// 需要调用方法
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>

4.4 pinia持久化

快速开始 | pinia-plugin-persistedstate (prazdevs.github.io)

我们的响应式数据变更之后,如果刷新页面,响应式数据会重置,如果我们需要对响应式数据进行一个持久化,那么就可以使用上面的插件。

安装:npm i pinia-plugin-persistedstate

配置:

js 复制代码
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

用法:

创建 Store 时,将 persist 选项设置为 true

js 复制代码
import { defineStore } from 'pinia'

export const useStore = defineStore(
  'main',
  () => {
    const someState = ref('你好 pinia')
    return { someState }
  },
  {
    persist: true, //实际上就是加了一个参数,第三个参数把persist改成true
  },
)

还有一些配置操作,可以参考官网:
配置 | pinia-plugin-persistedstate (prazdevs.github.io)

例如,我不希望把整个 state 进行持久化,我们可以使用 path 进行注册

js 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue';
export const useTestStore = defineStore('testStore', () => {
    
    const count = ref(0);
    const name = ref('feixin')
    const subCount = () => {
        count.value--;
    }
    const addCount = () => {
        count.value++;
    }

    return{
        count,
        subCount,
        addCount,
        name,
    }
},{
    persist: {
        paths:['count'] // 这里就只对 count 进行了持久化,而name没有
    }
})

5. 常用指令

指令 作用
v-bind 为HTML标签绑定属性值,如设置href,css样式等, v-bind:href 可以省略为 :href
v-model 在表单元素上创建双向数据绑定
v-on 为HTML标签绑定事件
v-if 类下
v-else-if 条件性的渲染某元素,判定为true时渲染,否则不渲染
v-else 类上
v-show 根据条件展示某元素,区别在于切换的是display属性的值
v-for 列表渲染,遍历容器的元素或者对象的属性

v-bind 和 v-model

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue test</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <a v-bind:href="url">这是一个链接</a>
        <!-- v-bind:href 可以省略为 :href -->
        <input type="text" v-model="url">
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data:{
           url:"https://www.baidu.com"
        }
    })
</script>
</html>

可以实现更改表单中的网址,旁边的a标签绑定的网址也会发生相应的变化

注意:通过 v-bind 或者 v-model 绑定的变量,必须在数据模型中声明。


v-on

可以绑定很多时间比如click,blur,focus, 与 js 事件类似

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue test</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="button" value="click me" v-on:click="handle()">
        <!-- v-on:click可以简化为@click -->
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            url: "https://www.baidu.com"
        },
        methods: {
            handle: function () {
                alert("i have been clicked");
            }
        },
    })
</script>

</html>

效果就是点击后触发事件


条件指令 v-if v-else-if v-else v-show:

if,else-if,else 是一起配套使用的

例如:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue test</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        年龄:<input type="text" v-model="age">经判定,为:
        <span v-if="age<35">年轻人 35岁以下</span>
        <span v-else-if="age>=35 && age<=60">中年人 35-60</span>
        <span v-else>老年人 60以上</span>
        <!-- 注意这里else后面没东西了 -->
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            age:20,
        },
        
    })
</script>

</html>

效果为修改输入框中的值,后面的判定字会改变,if 这一套 如果 条件为 else 的话标签直接不会在浏览器中被渲染,也就是根本不会出现在浏览器源码当中。

v-show:

上述效果同样可以通过v-show来实现。

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue test</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        年龄:<input type="text" v-model="age">经判定,为:
        <span v-if="age<35">年轻人 35岁以下</span>
        <span v-else-if="age>=35 && age<=60">中年人 35-60</span>
        <span v-else>老年人 60以上</span>
        <br><br>
        年龄:<input type="text" v-model="age">经判定,为:
        <span v-show="age<35">年轻人 35岁以下</span>
        <span v-show="age>=35 && age<=60">中年人 35-60</span>
        <span v-show="age>60">老年人 60以上</span>
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            age:20,
        },
        
    })
</script>

</html>

效果是一样的,区别在于v-show 如果条件为 false 的话标签依然会被浏览器渲染,不过是被display:none设置了不展示


v-for: 遍历数据对象

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue test</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">
        <div v-for="addr in addrs" :key="index">
            {{addr}}
        </div>
        <hr>
        <div v-for="(addr, index) in addrs" :key="index">
            {{index + 1}} : {{addr}}
        </div>
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            addrs:["beijing","shanghai","xian","guilin"]
        },
        
    })
</script>

</html>

6. Element -plus

6.1 安装

安装 | Element Plus (element-plus.org)

根据文档,在当前目录下安装

或者使用以下方式:

vue3+vite2增加element-plus的CDN链接打包构建 - 掘金 (juejin.cn)

按需引入:

  1. pnpm element-plus

  2. pnpm add -D unplugin-vue-components unplugin-auto-import

  3. 在vite.config.js中配置:

    js 复制代码
    import AutoImport from 'unplugin-auto-import/vite'  //---1
    import Components from 'unplugin-vue-components/vite' //---2
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'//---3
    
    export default defineConfig({
      plugins: [
        vue(),
        AutoImport({
          resolvers: [ElementPlusResolver()] //---1
        }),
        Components({
          resolvers: [ElementPlusResolver()] //---2
        })
      ],
      resolve: {
        alias: {
          '@': fileURLToPath(new URL('./src', import.meta.url))
        }
      }
    })

6.2 使用

创建如下目录

ElementView.vue中编写

vue 复制代码
<script>
export default{
    
}
</script>

<template>
    <div>
        <el-row class="mb-4">
            <el-button>Default</el-button>
            <el-button type="primary">Primary</el-button>
            <el-button type="success">Success</el-button>
            <el-button type="info">Info</el-button>
            <el-button type="warning">Warning</el-button>
            <el-button type="danger">Danger</el-button>
        </el-row>
		<!-- 各种你想添加的组件 -->	
    </div>
</template>
<style></style>

App.vue中编写

vue 复制代码
<script>
import ElementView from './views/element/elementView.vue';

export default{
    components: { ElementView }
}


</script>

<template>
    <div>
        <ElementView>

        </ElementView>
    </div>
</template>

<style>

</style>

即可导入。


6.3 常见组件

组件 | Element

进去复制粘贴使用,懂?


6.4 引入

引入组件之后需要在components中声明一下才可以使用

例如:

html 复制代码
<script>
import { Menu as IconMenu, Message, Setting } from '@element-plus/icons-vue'; 
// 这里引入了组件
export default {
    data() {
        return {
            searchForm: {
                name: "",
                gender: "",
                entryDate: [],
            }
        }
    },
    components: {
        Message, Setting
        //这里需要声明
    },
    methods: {
        query() {
            alert(JSON.stringify(this.searchForm));
        },
        sizeChange(val){
            alert("每页记录数变化" + val)
        },
        currentChange(val){
            alert("页码发生变化" + val)
        },
    }
}
</script>

7. pnpm

npm install -g pnpm


8. ESlint 配合 Prettier

参考旁边的文件 大事件管理系统中的 ESlint配置


9. husky

+ 别打上去

pnpm dlx husky-init && pnpm install

暂存区 eslint 校验


10. axios 配置

10.1. 创建 axios 实例

们会使用 axios 来请求后端接口, 一般都会对 axios 进行一些配置 (比如: 配置基础地址等)

一般项目开发中, 都会对 axios 进行基本的二次封装, 单独封装到一个模块中, 便于使用

  1. 安装 axios

    pnpm add axios

  2. 新建 utils/request.js 封装 axios 模块

    利用 axios.create 创建一个自定义的 axios 来使用

    http://www.axios-js.com/zh-cn/docs/#axios-create-config

js 复制代码
import axios from 'axios'

const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  // TODO 1. 基础地址,超时时间
})

instance.interceptors.request.use(
  (config) => {
    // TODO 2. 携带token
    return config
  },
  (err) => Promise.reject(err)
)

instance.interceptors.response.use(
  (res) => {
    // TODO 3. 处理业务失败
    // TODO 4. 摘取核心响应数据
    return res
  },
  (err) => {
    // TODO 5. 处理401错误
    return Promise.reject(err)
  }
)

export default instance
10.2. 完成 axios 基本配置
jsx 复制代码
import { useUserStore } from '@/stores/user'
import axios from 'axios'
import router from '@/router'
import { ElMessage } from 'element-plus'

const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  baseURL,
  timeout: 100000
})

instance.interceptors.request.use(
  (config) => {
    const userStore = useUserStore()
    if (userStore.token) {
      config.headers.Authorization = userStore.token
    }
    return config
  },
  (err) => Promise.reject(err)
)

instance.interceptors.response.use(
  (res) => {
    if (res.data.code === 0) {
      return res
    }
    ElMessage({ message: res.data.message || '服务异常', type: 'error' })
    return Promise.reject(res.data)
  },
  (err) => {
    ElMessage({ message: err.response.data.message || '服务异常', type: 'error' })
    console.log(err)
    if (err.response?.status === 401) {
      router.push('/login')
    }
    return Promise.reject(err)
  }
)

export default instance
export { baseURL }

11. 打包

npm run build 可以进行打包,打包之后会出现在dist中

相关推荐
拉不动的猪6 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程23 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041230 分钟前
Netty编解码器详解与实战
前端
袁煦丞35 分钟前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
qsmyhsgcs35 分钟前
Java程序员转人工智能入门学习路线图(2025版)
java·人工智能·学习·机器学习·算法工程师·人工智能入门·ai算法工程师
Humbunklung1 小时前
PySide6 GUI 学习笔记——常用类及控件使用方法(常用类矩阵QRectF)
笔记·python·学习·pyqt
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html