Vue3复习笔记

前言

适合于看了vue2之后学习vue3的学习者复习vue3使用

可根据目录按需查阅

觉得这里主题看着不舒服可以去这里看
vue3备忘录

1、创建项目

  • 使用npm

    javascript 复制代码
    npm init vue@latest
    javascript 复制代码
    npm i
    javascript 复制代码
    npm run dev
  • 使用pnpm

    javascript 复制代码
    pnpm create vue@latest
    javascript 复制代码
    pnpm i
    javascript 复制代码
    pnpm dev

2、reactive和ref

  • reactive可以将对象类型的数据转换为响应式的数据

  • ref可以将简单类型和对象类型的数据转换为响应式的数据

    但是ref转换简单类型的数据的本质是把简单类型的数据外面包一层转换为对象类型的数据

  • reactive的使用

    javascript 复制代码
    import { reactive } from 'vue'
    
    const msg = reactive({
        count: 100
    })
    
    {{ msg.count }}
    
    @click="msg.count++"
  • ref的使用

    javascript 复制代码
    <script setup>
    import { ref } from 'vue'
    
    const count = ref(0)  // 在括号里面填写数据
    
    const addCount = () => {
      count.value++
    } // 在script脚本中使用是需要加上.value
    </script>
    <template>
      {{ count }} // 在template里面使用时
      <button @click="count++">按钮</button> // 这里也是在template里面所以访问修改直接使用count
    </template>

    ref在template里面时直接使用名称即可访问

    在script脚本里面使用时需要加上==.value==

最佳实践:统一使用ref定义响应式数据

3、定义方法

  • 直接定义为

    javascript 复制代码
    const 方法名 = () => {
        方法逻辑
    }
  • 在基于setup语法糖的情况下后面可以直接调用

4、计算属性

  • 先导入

    javascript 复制代码
    import { computed } from 'vue'
  • 简单写法

    javascript 复制代码
    const 计算属性名 = computed(() => {
        return 计算后的值
    })
  • 完整写法

    javascript 复制代码
    const 计算属性名 = computed({
      get: () => {
        return 计算后的值
      },
      set: (val) => {
        编写逻辑
      }
    })

最佳实践:避免直接修改计算属性的值,除特殊情况无法避免

5.watch侦听

  • 先导入

    javascript 复制代码
    import { watch } from 'vue'
  • 侦听单个

    javascript 复制代码
    watch(监听的ref对象, (newVal, oldVal) => {
        发生变化时执行的逻辑
    })
  • 侦听多个

    javascript 复制代码
    watch([监听的ref对象1, 监听的ref对象2], (newVal, oldVal) => {
        发生变化时执行的逻辑
        此时的 newVal 是 [ref对象1的值, ref对象2的值] 
    })
  • 深度侦听

    javascrpt 复制代码
    watch(监听的ref对象, (newVal, oldVal) => {
    	逻辑  
    },{
    	immediate: true,  // 立即执行一次逻辑
    	deep: true		  // 开启深度侦听
    })
  • 精确侦听对象中的某个值

    javascript 复制代码
    watch(
      () => 对象.value.键名,
      (newVal, oldVal) => 发生变化时执行的操作
    )

在不开启深度侦听的情况下

watch进行的是浅层侦听

就是只有当整个发生变化时才会触发

eg:[1, 2, 3, 4, 5, 6] 如果 把整个数组都改变 那浅层也能侦听到

​ 如果只改了数组里面的某一个元素的值,那就只有开启深度侦听才能侦听到

6、生命周期函数

vue2 vue3 时机
created setup 一进来就调用(实例初始化完成以后调用)
mounted onMounted 实例挂载到DOM完成后调用

注意vue3中的声明周期函数需要导入,完整语法演示如下

javascript 复制代码
import { onMounted } from 'vue'

<script setup>
  const getData = () => {
    console.log("发送请求,获取数据")
  }
  
  onMounted(() => {
    console.log("触发onMounted生命周期函数")
  })

  getData() // 调用setup生命周期函数 与写的位置无关 此项会在onMounted之前执行
  
</script>

可以多次调用,多次调用时会按顺序执行,不会冲突

7、组件注册

  • 局部导入

    在script里面导入后可以直接使用

    不需要注册

    javascript 复制代码
    <script setup>
    // 导入
    import SonCom from '@/components/son-com.vue'
    </script>
    
    <template>
      <div>
        这是父组件的区域,下面是子组件
    	// 直接使用
        <son-com></son-com>
      </div>
    </template>

8、父传子(对应vue2中的props)

  • 在父组件中给子组件标签添加自定义属性

  • 在子组件中使用

    javascript 复制代码
    const props = defineProps({
      自定义属性名称: 类型
    })
    
    // 或完整写法
    const props = defineProps({
      自定义属性名: {
        type: 类型,
        // 更多配置项
      }
    })
  • 在子组件中对于props传递过来的数据

    • 在模版中( template )

    • 可以直接使用自定义属性名访问

      javascript 复制代码
      {{ 自定义属性名 }}
    • 在脚本中( script )

    • 必须使用props.自定义属性名的格式才能访问

      javascript 复制代码
      props.自定义属性名
  • 也可以传递动态的值使用:data

9、子传父(对应vue2中的$emit)

  • 在子组件中使用编译器宏注册自定义事件

  • 在父组件中监听自定义事件

  • 子组件中

    javascript 复制代码
    const emit = defineEmits(['自定义事件名'])
    
    emit('自定义事件名', 数据)
  • 父组件中

    javascript 复制代码
    @自定义事件名 = ""

    注意在这里的自定义事件名后面同样跟vue2一样可以直接使用$event直接获取传过来的参数

10、模版引用和defineExpose(对应vue2中的ref和$refs)

  • 首先定义一个ref对象里面

  • 然后使用ref绑定到标签

  • 后续可以使用名称.value获取dom对象或组件实例

  • 获取dom对象演示

    javascript 复制代码
    const Href = ref(null)
    
    <input type="text" ref="Href"></input>
    
    // 获取
    
    onMounted(() => {
      console.log(Href.value) // 获取dom对象
      Href.value.focus() // 聚焦输入框
    })
  • 获取组件实例演示

    javascript 复制代码
    const Gref = ref(null)
    
    <HmCom ref="Gref"></HmCom> // 绑定到组件
    javascript 复制代码
    // 在组件中
    const data = "这是一个数据"
    const getData = () => {
        console.log(data)
    }
    
    使用defineExpose()将数据暴露出去
    
    defineExpose({
        data,
        getData
    })
    javascript 复制代码
    const Gref = ref(null)
    
    <HmCom ref="Gref"></HmCom> // 绑定到组件
    
    // 获取
    Gref.value.data // 获取 data 数据
    Gref.value.getData() // 调用 getData 方法,可以正常调用使用

使用**defineExpose({})**暴露属性方法

11、provide和inject

  • 用于跨多层组件的通信

  • 在父组件中

    javascript 复制代码
    import { provide } from 'vue'
    
    provide('名称', 数据) // 可以传静态数据也可以传响应式数据
    provide('名称', (val) => {
        也可以传递函数
    })
  • 在子孙组件中

    javascript 复制代码
    import { inject } from 'vue'
    
    const message = inject('名称') // 接收数据
    // 如果是响应式的ref数据同样可以直接使用 {{ message }} 渲染
    const 函数名称 = inject('传过来的函数名称')
    
    函数名称(参数值)

注意只能用于更高层的组件向自己的子孙组件传递

不能反过来

12、defineOptions

  • 这里面可以写OptionsAPI中的内容

  • 原因是有些属性不能再setup里面写

  • 演示

    javascript 复制代码
    <script setup>
      defineOptions({
        name: 'LoginIndex'  
      })  
    </script>

    比如给组件命名这样的操作就需要在这里面写

    写在里面的内容是与setup平级的

13、defineModel

  • 在vue2中v-model是通过绑定value属性和监听==@input==事件来实现双向绑定

  • 在vue3中v-model改为了绑定modelValue和监听==@updata:modelValue==

    注意vue3中的v-model等于v-model:modelValue

    可以改写为v-mode:任意名称

    此时相当于绑定了任意名称和监听==@updata:任意名称==

    相当于做了vue2中的.sync的结合

  • 演示:

    父组件:

    javascript 复制代码
    <script setup>
    import SonCom from '@/components/son-com.vue'
    import { ref } from 'vue'
    const data = ref('100')
    
    </script>
    <template>
      <div>
        <h1>{{ data }}</h1>
        <son-com v-model="data"></son-com>
      </div>
    </template>

    子组件:

    javascript 复制代码
    <script setup>
    const props = defineProps({
      modelValue: String
    })
    const emit = defineEmits(['update:modelValue'])
    </script>
    <template>
      <input type="text" :value="modelValue" @input="e => emit('update:modelValue', e.target.value)">
    </template>
    <style></style>
  • 为了解决这个繁琐的操作,提供了defineModel编译器宏

    这个功能在vue3.3中是实验性功能,在vue3.4中正式发布

  • 首先在父组件中通过v-model传值给子组件

    javascript 复制代码
    const data = ref('100')
    
    <son-com v-model="data"></son-com>
  • 然后在子组件中使用defineModel接收

    javascript 复制代码
    const 自定名称 = defineModel()
    
    下面就可以使用修改这个值了(相当于已经实现双向绑定)
    
    <input type="text" :value="自定名称" @input="e => 自定名称 = e.target.value">

在父组件中用v-model将数据传过去

然后在子组件中使用defineModel接收

然后在子组件中就可以使用和修改这个数据,且父组件中可以同步修改

14、Pinia(相当于vuex)

  • 定义

    javascript 复制代码
    // 新建一个store文件夹用于存放pinia仓库中的数据
    import { defineStore } from 'pinia'
    export const useChannelStore = defineStore('仓库名称', () => {
      const list = ref([]) // 相当于 vuex 中的 state
      const setList = () => {
        // 这里面可以直接修改上面的数据
      }
      const getList = computed(() => {
          return 数据 // 这个相当于之前的的getters
      })
    })
  • 使用

    javascript 复制代码
    // 在想要使用的组件中导入
    import { 定义时导出的名称 } from '@/...'
    
    const 自定义名称 = 定义时导出的名称() 
    
    // 然后就可以直接使用
    自定义名称.list
    自定义名称.setList()
    自定义名称.getList
  • 表格对比

    Vuex Pinia 备注
    mutations 没有 修改vuex中用于修改state种的数据,pinia中可以直接修改,不需要
    state const data = ref() Pinia中直接定义数据就是state中的数据
    getters const getList = computed(() => { return 返回数据 }) Pinia中直接定义computed就是计算属性
    actions const 函数名 = () => { 函数内容 } 在Pinia中可以直接在函数中执行同步或者异步操作

注意在

const 自定义名称 = 定义时导出的名称()

此处导入时如果直接对==数据(普通数据、计算属性)==使用解构则会丢失响应式

可以对方法直接解构

对数据解构的话要使用

const { 解构数据 } = storeToRefs(自定义名称)

要多写一行,不能直接const { 解构数据 } = 定义时导出的名称()

且需要导入import { storeToRefs } from 'pinia'

15、Pinia数据持久化

开始 | Pinia Plugin Persistedstate

  • 下载插件

    bash 复制代码
    pnpm add pinia-plugin-persistedstate
  • 在main.js中对piniause这个插件对象

    javascript 复制代码
    import { createPinia } from 'pinia'
    import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
    
    const pinia = createPinia()
    pinia.use(piniaPluginPersistedstate)
  • 使用时

    javascript 复制代码
    // 对你创建的defineStore添加第三个参数
    persist: true
    
    // eg:
    export const counterStore = defineStore('counter', () => {
        // .....
        return {  }
    }, {
        persist: true // 添加这个
    })
  • 这时刷新页面数据就会持久化存储不会重新初始化

  • 如果需要对插件进行配置

    javascript 复制代码
    export const counterStore = defineStore('counter', () => {
      // .....
      return {  }
    }, {
      persist: {
        // 在这里面填写配置项
      }
    })

16、路由配置

vue3中的路由配置与vue2中有所不同的地方,但是大致相同,初始化项目后配置如下

javascript 复制代码
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [],
})

export default router
  • createWebHistory是指以history模式创建

  • createWebHashHistory是以hash模式创建

  • 里面的参数是路径的前缀,默认是/

    如果import.meta.env.BASE_URL换成/aa,那么所有的路径前面都会加上/aa,eg:localhost:3000/aa/list

    import.meta.env这个是环境变量的前缀,这里的是base环境变量,可以在vite.config中通过base配置项更改

  • 区别

    Vue版本 获取路由对象 获取路由信息 备注
    2 this.$router $route 无需导入
    3 useRouter() useRoute() 需要导入
    • 演示

      javascript 复制代码
      <script setup>
      import { useRouter, useRoute } from 'vue-router'
      const router = useRouter()
      const route = useRoute()
      router.push()
      route.query.参数名
      </script>
  • 拓展:

    • 直接导入的router对象

      javascript 复制代码
      import router from '@/router'
      
      router.push('/home')
    • 和使用钩子函数导入的

      javascript 复制代码
      // 导入方式
      import { useRouter } from 'vue-router'
                    
      const router = useRouter()
      router.push('/home')

    区别:

    前者可以在任何地方使用,后者由于useRouter()只能在setup中调用,所以后者只能在组件中使用

17、element-plus的使用

  • 对应vue2中的element-ui

  • 参考官网设计 | Element Plus

  • 执行下面的命令

    bash 复制代码
    pnpm install element-plus
    pnpm install -D unplugin-vue-components unplugin-auto-import
  • 将下面代码集成到vite.config.js

    javascript 复制代码
    import { defineConfig } from 'vite'
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
    
    export default defineConfig({
      // ...
      plugins: [
        // ...
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],
    })
  • 接下来就可以直接使用了,会自动导入

  • 注册完成过后你的组件注册也可以直接使用

    他会自动导入

    javascript 复制代码
    <script setup>
     // 不需要在这里引入
    </script>
    <template>
     <el-button>按钮</el-button>
     <HmCom></HmCom>
    </template>

18、axios拦截器的配置(拓展)

  • 官方文档Axios 实例 | Axios中文文档 | Axios中文网

  • 配置

    javascript 复制代码
    const instance = axios.create({
      baseURL, // 请求链接
      timeout: 5000, // 超时时间
    })
    
    instance.interceptors.request.use(
      (config) => {
        if (TokenStore.token) {
          config.headers.Authorization = TokenStore.token // 如果有token的话配置响应头 Authorization 专门用来设置token
        }
        return config
      },
      (err) => {
        Element.error('请求配置阶段出错,请刷新页面重试') // 额外反应
        Promise.reject(err) // 这个相当于是告知失败 但他不会处理失败(页面不会有额外反应)
      },
    )
    
    instance.interceptors.response.use(
      (res) => {
        if (res.data.code === 0) {
          // res.data 是返回的那个东西的整体
          return res
        }
        ElMessage.error(res.data.message || '服务异常')
        return Promise.reject(res.data) // 返回一个对象类型的
      },
      (err) => {
        ElMessage.error(err.response.data.message || '服务异常') // err.response.data.messsage 可以获取错误的具体信息
        if (err.response?.status === 401) {
          router.push('/login')
        }
        return Promise.reject(err)
      },
    )

19、element-plus表单组件的使用

  • 官方文档Form 表单 | Element Plus

  • 自定义校验规则步骤

    • 基础模版

      html 复制代码
      <el-form>
        <el-item>
        	<el-input></el-input>  
        </el-item>
      </el-form>
    • 1、首先定义一个响应式的对象用于存放校验的数据

      javascript 复制代码
      const userForm = ref({
          username: '',
          password: '',
          repassword: ''
      })
    • 2、定义一个非响应式的对象用于存放校验规则

      javascript 复制代码
      const rules = {
          username:[
              { required: true, message: '请输入密码', trigger: 'blur' },
              { min: 3, max: 10, message: '用户名必须是 3 - 10 位', trigger: 'change' }
          ],
          password:[
              { validator: (rule, value, callback) => {
                  // rule 为当前校验规则的相关信息
                  // value 为当前的表单元素值
                  // callback 代表的是是否通过校验通过callback(new Error(错误信息))来返回错误信息
              } } // 这里没有配置 trigger 默认为 change
          ]
      }

      一个里面可以填写多条规则,每条规则以对象的形式编写

      trigger中有两个值

      blur代表 失焦时进行规则校验

      change代表 发生改变时进行规则校验

      自定义校验时注意callback( )无论成功失败都要返回

      成功callback()

      失败callback(new Error(错误信息))

      且最好不要省略else

      即:

      javascript 复制代码
      if(...){
         callback()
      }else{
          callback(new Error(错误信息))
      }
      // 最好不要写成下面的形式
      if(...){
         callback()
      }callback(new Error(错误信息))

      当存在validator时可以填写其他信息,但是此时的其他信息会被视为自定义属性,不会被视为校验规则

      eg:

      javascript 复制代码
      repassword: [
          { pattern: /^\S{6,15}$/, message: '密码必须为6-15位的非空字符', trigger: 'blur' },
          {
            min: 7,
            validator: (rule, value, callback) => {
              if (value !== userForm.value.password) {
                callback(new Error('两次输入密码不一致'))
              } else { callback() }
            }
          }
      ]
      • 此时的min不会被视为校验规则,只会被视为一个普通的自定义属性
    • 3、将userForm通过:model绑定到el-form,将rules通过:rules绑定到el-form

      html 复制代码
      <el-form :model="userForm" :rules="rules">
        <el-form-item>
        	<el-input></el-input>  
        </el-form-item>
      </el-form>
    • 4、给el-input通过v-model绑定userForm中的对应属性

      html 复制代码
      <el-form :model="userForm" :rules="rules">
        <el-form-item>
        	<el-input v-model="userForm.username"></el-input>  
        </el-form-item>
      </el-form>
    • 5、给el-item通过prop绑定rules中的对应属性注意不需要"对象.属性"

      html 复制代码
      <el-form :model="userForm" :rules="rules">
        <el-form-item prop="username"> 注意此处
        	<el-input v-model="userForm.username"></el-input>  
        </el-form-item>
      </el-form>
  • 拓展:

    注意事项

    在配置了拦截器时,调用接口后不要使用alert()他会使拦截器里面的有些方法失效

    eg:

    javascript 复制代码
    const register = async () => {
      // 注册成功之前先再次验证 验证成功之后开始注册逻辑 验证失败的话他也会自动给出提示
      await form.value.validate()
      await userRegisterService(userForm.value)
      ElMessage.success('注册成功')
      // alert('注册成功') 这里如果使用了 alert() 的话 拦截器中的 ElMessage.error() 不会生效
      isRegister.value = false
    }
    • form.value.validate( )是按需进行验证的,他会自动的匹配当前表单中有的项目进行验证,没有的他不会验证,因为这一点,可以给登录注册共用一个对象进行绑定,在验证时也不会产生冲突

20、element-plus菜单组件的使用

  • 官方文档Menu 菜单 | Element Plus

  • 常用演示

    html 复制代码
    <el-menu
        active-text-color="#ffd04b" 
        background-color="#232323"
        :default-active="$route.path"
        text-color="#fff"
        router
    >
        <el-menu-item index="/article/channel">
          <el-icon><Management/></el-icon>
          <span>名称</span>
        </el-menu-item>
    </el-menu>
  • active-text-color这个参数是指激活时的文字颜色,就是点到哪个时哪个的文字颜色就会变成参数值

  • :default-active这个是默认激活的菜单项

  • router指的是开启vue-router模式当开启时,会在激活导航时以 index 作为 path 进行路由跳转 使用

    default-active来设置加载时的激活项

  • $route.path是指获取的当前路由

21、导航守卫

vue2导航守卫参考文档导航守卫 | Vue Router

vue3导航守卫参考文档导航守卫 | Vue Router

  • vue3中返回undefined或者true就是放行

    返回false就是拦回from的地址页面

  • return '/login'return { name: 'Login' } 就是返回具体地址

  • vue3导航守卫示例

    javascript 复制代码
    router.beforeEach((to) => {
      const userStore = useTokenStore()
      if ( !userStore.token && to.path !== '/login' ) {
        return '/login'
      }
    })

    vue3中不再通过next来进行拦截,而是通过返回值来进行判断

22、下拉菜单

  • 官方网站Dropdown 下拉菜单 | Element Plus

  • 示例代码

    html 复制代码
    <template>
      <el-dropdown @command="handleCommand">
        <span class="el-dropdown-link">
          Dropdown List<el-icon class="el-icon--right"><arrow-down /></el-icon>
        </span>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item command="a">Action 1</el-dropdown-item>
            <el-dropdown-item command="b">Action 2</el-dropdown-item>
            <el-dropdown-item command="c">Action 3</el-dropdown-item>
            <el-dropdown-item command="d" disabled>Action 4</el-dropdown-item>
            <el-dropdown-item command="e" divided>Action 5</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </template>
    javascript 复制代码
    const handleCommand = (key) => { // 这里的key就是触发时的对应参数 (这里是a、b、c、d、e)
      // 操作逻辑
    } 
  • 拓展

    javascript 复制代码
    const handCommand = async (key) => {
      if (key === 'logout') {
        await ElMessageBox.confirm('你确定要退出登录吗', '温馨提示', {
          type: 'warning',
          confirmButtonText: '确定',
          cancelButtonText: '取消'
        })
        tokenStore.removeToken()
        tokenStore.setUserInfo({})
        router.push('/login')
      } else {
        router.push(`/user/${key}`)
      }
    }

    使用asyncawait配合来达到消息确认框的效果

23、其余组件用法

由于组件用法较多此处不再一一演示

更多用法查阅官网即可

官网解释非常详细

相关推荐
羊吖2 小时前
Vue文件预览组件实战:高性能懒加载
前端·javascript·vue.js
d111111111d2 小时前
再STM32F103C8T6中小端存储和大端存储有什么不同,STM32F103C8T6用的是那个,为什么要这么使用?
笔记·stm32·单片机·嵌入式硬件·学习
代码or搬砖2 小时前
如何创建一个vue项目(详细步骤)
前端·javascript·vue.js
Chloeis Syntax2 小时前
MySQL初阶学习日记(5)--- 联合查询
java·笔记·学习·mysql
2301_801821712 小时前
两个模型整合问题解决
笔记
代码or搬砖2 小时前
使用nvm管理node多版本
vue.js·node.js
思成不止于此2 小时前
【MySQL 零基础入门】DQL 核心语法(三):学生表排序查询与分页查询篇
数据库·笔记·学习·mysql
yuguo.im2 小时前
【译】Vuejs: 使用带有对象的 v-model 来创建自定义组件
前端·javascript·vue.js
计算机学姐2 小时前
基于Python的高校后勤报修系统【2026最新】
开发语言·vue.js·后端·python·mysql·django·flask