VUE3

2,934 阅读5分钟

Vite创建的项目中使用less

  1. 直接安装less
npm install less -D
  1. 在组件style节点这样声明即可:
<style lang="less">
    ····样式
</style>

注册全局组件

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import Swiper from './components/globalComponents/Swiper.vue'
const app = createApp(App)
// 此处Swiper的name 就是定义组件时的name属性
app.component(Swiper.name, Swiper)
app.mount('#app')

绑定class

以对象语法绑定class

  <div>
    <h3 :class="{ italic: italicVariable, delete: deleteVariable }">
      我是一个测试class绑定的元素!
    </h3>
    <button @click="italicVariable = !italicVariable">切换斜体</button>
    <button @click="deleteVariable = !deleteVariable">切换删除</button>
  </div>

以对象语法绑定style

// fontSize的值也可以使用data中的变量
<h3 :style="{ fontSize: '23px' }">我是一个测试style绑定的元素!</h3>

props的自定义用法

  1. 自定义验证的方法
  props: {
    status: {
    //自定义验证方法, 返回true表示验证通过
      validator(val) {
        console.log(val)
        return ['success', 'warning', 'error'].indexOf(val) > -1
      },
    },
  }
  1. 用ts验证,并且设置默认值
import { defineProps, withDefaults } from 'vue'
import type { PersionsList } from '@/types/index'
const prosp = withDefaults(defineProps<{ list?: PersionsList }>(), {
  list: () => [{
    id: '123',
    name: 'def',
    age: 90
  }]
})

自定义组件实现v-model

实现方式1

image.png

父组件

<fnts-swiper v-model:number="count"></fnts-swiper>

setup() {
   const count = ref(0)
   return {
     count,
   }
}

子组件

<button @click="addCount">count++</button>
props: {
    number: {
      type: Number,
      required: true,
    },
},
setup(props, context) {
    const addCount = () => {
      context.emit('update:number', props.number + 1)
    }
}

实现方式2

父组件中

<TodoButton v-model="val"></TodoButton>

子组件中

props: {
    modelValue: {
      type: Number,
      required: true,
      default() {
        return 0
      },
    },
},
setup(props, context) {
    const inputVal = (val) => {
      context.emit('update:modelValue', val)
    }
},

vue中组件的名字

如果在组件中默认导出了name,则根据导出的name定义名字

<script lang="ts">
    export default {
      name: 'HelloWorld'
    }
</script>

如果没有导出则根据文件名定义组件名

为了不用写冗余的代码定义组件的名字,

  1. 可以安装一个插件 npm i vite-plugin-vue-setup-extend -D
  2. 在vite.config.ts引入插件 import VueSetupExtend from 'vite-plugin-vue-setup-extend'
  3. 在plugins中调用插件
plugins: [
    vue(),
    VueSetupExtend()
],

问题:在使用vite-plugin-vue-setup-extend 0.4.0及以前版本时,会有个问题:如果script标签没内容,即使给script标签添加上name属性,其在vue-devtools内也不会生效。

解决办法:不要让script标签内空着,例如:加行注释

<script lang="ts" setup name="Ceshi">
// 注释
</script>

toRefs作用

由reactive定义的对象可以使用toRefs进行解构赋值操作,并且解构后的属性和reactive声明的对象有关联,当改变解构后属性的值时,原reactive声明的对象属性也会同时发生改变

toRef作用

toRefs可以同时将多个reactive定义的对象的属性进行解构为RefImpl对象,但是toRef一次只能将一个属性变为RefImpl对象

watch 函数

watch监视ref定义的基本类型数据,以及解除监视

watch监视ref定义的引用类型数据

watch:监视【reactive】定义的【引用类型】数据,且默认开启深度监视

watch:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性

  1. 若该属性值不是【对象类型】,需要写成函数形式。
  2. 若该属性值是【对象类型】,建议写成getter函数并配置deep:true. 因为如果不写成getter函数,则无法监听整个对象的改变。如果不写deep:true则无法监听【基本类型】数据的改变

watch:同时监视多个属性

vue3 父子组件生命周期狗子的执行顺序

创建时:

  1. 父组件 -- setup
  2. 父组件 -- onBeforeMount
  3. 子组件 -- setup
  4. 子组件 -- onBeforeMount
  5. 子组件 -- onMounted
  6. 父组件 -- onMounted

卸载时

  1. 父组件 -- onBeforeUnmount
  2. 子组件 -- onBeforeUnmount
  3. 子组件 -- onUnmounted
  4. 父组件 -- onUnmounted

vue-router

  1. 路由切换时,视觉效果上“消失”了的路由组件,默认是被卸载掉的,需要的时候再去挂载

路由的工作模式

  1. history 模式

优点: URL更加美观,不带有#,更接近传统网站的URL。 缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。

const router = createRouter({
    history:createWebHistory(),
    /*******/
})
  1. hash模式

优点:兼容性更好,因为不需要服务器端处理路径。 缺点:URL带有#不太美观,且在SEO优化方面相对较差

const router = createRouter({
    history:createWebHashHistory(),
    /*******/
})

路由的传参方式

第一种传参以及如何接收参数 query

// 传递的参数
<template>
<RouterLink :to="`/news/detail?id=${item.id}&title=${item.title}&content=${item.content}`">{{ item.title }}
</RouterLink>
</template>

路由配置不用改变

// 接收参数
import { useRoute } from 'vue-router';
const route = useRoute();

第二种传参以及如何接收参数 query

// 传递的参数
<RouterLink :to="{
  path: '/news/detail',
  query: {
    id: item.id,
    title: item.title,
    content: item.content
  }
}">{{ item.title }}
</RouterLink>

路由配置不用改变

接收参数参考第一种(与第一种一样)

第三种传参以及如何接收参数 params

  1. 传递参数
<RouterLink :to="`/news/detail/${item.id}/${item.title}/${item.content}`">{{ item.title }}
</RouterLink>
  1. 配置路由
{
    path: '/news',
    component: News,
    redirect: '/news/detail/default/default/default',
    children: [
        {
            path: 'detail/:id/:title/:content',
            component: Detail
        }
    ]
}
  1. 接收参数
import { useRoute } from 'vue-router';
const route = useRoute();
console.log(route.params)

第四种传参以及如何接收参数 params

  1. 传递参数

to使用对象形式传递params参数时只能使用name, 不可使用path

<RouterLink :to="{
  name:'detail',
  params:{
    id:item.id,
    title:item.title,
    content:item.content
  }
}">{{ item.title }}
</RouterLink>
  1. 配置路由
{
    path: '/news',
    component: News,
    redirect: '/news/detail',
    children: [
        {
            name: 'detail',
            // 问号可以限制必要性
            path: 'detail/:id?/:title?/:content?',
            component: Detail
        }
    ]
},
  1. 接收参数
import { useRoute } from 'vue-router';
const route = useRoute();
console.log(route.params)

路由的props配置

第一种 props:true; 处理params参数为props
  1. 传递参数
<RouterLink :to="{
  name:'detail',
  params:{
    id:item.id,
    title:item.title,
    content:item.content
  }
}">{{ item.title }}
</RouterLink>
  1. 配置路由
{
    path: '/news',
    component: News,
    redirect: '/news/detail',
    children: [
        {
            name: 'detail',
            // 问号可以限制必要性
            path: 'detail/:id?/:title?/:content?',
            component: Detail,
            props:true
        }
    ]
},
  1. 接收参数
defineProps(['id', 'title', 'content'])
第二种 处理query 参数为props
  1. 传递参数
<RouterLink :to="{
  path: '/news/detail',
  query: {
    id: item.id,
    title: item.title,
    content: item.content
  }
}">{{ item.title }}
</RouterLink>
  1. 配置路由
{
    path: '/news',
    component: News,
    redirect: '/news/detail',
    children: [
        {
            name: 'detail',
            path: 'detail',
            component: Detail,
            props(route) {
                return route.query
            }
        }
    ]
},
  1. 接收参数
defineProps(['id', 'title', 'content'])

编程式路由导航

push的参数同RouterLInk标签的to

import { useRouter } from 'vue-router'
const router = useRouter();
router.push({
  path: '/news/detail',
})

Pinia

  1. 在main.js中
import {createPinia} from 'pinia'
const pinia = createPinia();
app.use(pinia);
  1. 创建store文件夹,以及新建对应文件 ··· import { defineStore } from 'pinia' import { ref } from 'vue'

export const useCountStore = defineStore('count', () => { const sum = ref(0); return { sum } }) ··· 3. 使用store

import { useCountStore } from '@/store/count'
const countStore = useCountStore();
const { sum } = toRefs(countStore);

mitt

  1. 创建mitt
import mitt from 'mitt';
const emitter = mitt();
export default emitter
  1. 订阅事件
import emitter from '@/utils/mitt';
const toy = ref();
emitter.on('send-toy', (val) => {
    console.log('val',val)
    toy.value = val
})
onUnmounted(() => {
    emitter.off('send-toy')
})
  1. 发布事件
import emitter from '@/utils/mitt';
const toy = ref('奥特曼')
onMounted(() => {
    emitter.emit('send-toy', toy.value)
})

customRef

import { customRef } from 'vue'

export const useCustomerRef = (val: string | number, duration?: number) => {
    let timer: any;
    const refVal = customRef((track, tigger) => {
        return {
            get() {
                track();
                return val;
            },
            set(newVal) {
                //此处写要处理的逻辑
                clearInterval(timer);
                timer = setTimeout(() => {
                    val = newVal;
                    tigger();
                }, duration)
            }
        }
    })
    return refVal
}