Vue3的语法使用

148 阅读4分钟

setup 内部写法

定义数据

  1. 死数据,不可以修改之类的,但是可以展示视图层。let str = '1';

  2. 响应式数据 : ref

【在使用的时候需要 : x.value】

3.响应式数据 : reactive

在使用的时候需要 : 不像ref一样,【不需要.value】

reactive 只能写【对象或者数组】

Vue2 和 Vue3数据拦截不同的点

Vue2.x ==> Object.defineProperty

Vue3.x ==> new Proxy

toRefs

解构==》响应式数据

let obj = reactive({
        name:'张三',
        age:20
})

let { name,age } = toRefs( obj );

computed

computed有两种写法

1>  let changeStr = computed(()=>{
        return str.value;
    })

2>  let changeStr = computed({
        get(){
                return str.value;
        },
        set( val ){
                str.value = val;
        }
    })

watch

1> 监听某一个数据

        watch( str , (newVal,oldVal)=>{
                console.log( newVal,oldVal);
        })
        
2> 同时监听多个数据

        watch( [ str , num ] , (newVal,oldVal)=>{
                console.log( newVal,oldVal);
        })
        
3> 初始化监听

        watch( num , (newVal,oldVal)=>{
                console.log( newVal,oldVal);
        },{
                immediate:true
        })

4> 监听对象

        watch( obj , (newVal)=>{
                console.log( newVal )
        },{
                immediate:true,
        })

5> 监听对象某一个key,并且深度监听

        watch( ()=>obj.m , (newVal,oldVal)=>{
                console.log( newVal,oldVal )
        },{
                immediate:true,
                deep:true
        })

6. 立即执行监听函数

        watchEffect(()=>{
                console.log( str.value )
        })

7. 监听路由

        let router = useRouter();

        watch( ()=>router.currentRoute.value,( newVal )=>{
                console.log( newVal );
        },{
                immediate:true
        })

vue-router

vue-router : router.vuejs.org/zh/api/

tag属性去除了

<router-link to='/about' tag='div'>跳转到关于我们</router-link>

写法问题

let router = useRouter(); ===> this.$router

let route = useRoute(); ===> this.$route

导航守卫

全局路由守卫

beforeEach(to, from, next) 全局前置守卫,路由跳转前触发
beforeResolve(to, from, next) 全局解析守卫 在所有组件内守卫和异步路由组件被解析之后触发
afterEach(to, from) 全局后置守卫,路由跳转完成后触发

路由独享守卫

beforeEnter(to,from,next) 路由对象单个路由配置 ,单个路由进入前触发

组件路由守卫	
beforeRouteEnter(to,from,next) 在组件生命周期beforeCreate阶段触发
beforeRouteUpdadte(to,from,next) 当前路由改变时触发
beforeRouteLeave(to,from,next) 导航离开该组件的对应路由时触发

生命周期

选项式 API 【 beforeCreate ... 】

setup 组合式API

注意:没有beforeCreate和created 其他生命周期要使用前面加"on" 例如:onMounted

组件

父传子

1. 父

    <template>
        <div>
            <List :msg='msg'></List>
        </div>
    </template>

    <script setup>
    import List from '../components/List.vue'
    let msg = ref('这是父传过去的数据');
    </script>

2. 子

    <template>
        <div> 
            这是子组件 ==> {{ msg }}
        </div>
    </template>

    <script setup>
    defineProps({
            msg:{
                    type:String,
                    default:'1111'
            }
    })
    </script>

子传父

子:
    <template>
        <div> 
            这是子组件 ==> {{ num }}
            <button @click='changeNum'>按钮</button>
        </div>
    </template>

    <script setup lang='ts'>
    let num = ref(200);

    const emit = defineEmits<{
      (e: 'fn', id: number): void
    }>()

    const changeNum = ()=>{
            emit('fn',num)
    }	
    </script>

父:
    <template>
            <div>
                    <List @fn='changeHome'></List>
            </div>
    </template>

    <script setup>
    import List from '../components/List.vue'
    const changeHome = (n)=>{
            console.log( n.value );
    }
    </script>

v-model传值

父:
    <List v-model:num='num'></List>
    <script setup>
    import List from '../components/List.vue'
    let num = ref(1);
    </script>
子:
    const props = defineProps({
            num:{
                    type:Number,
                    default:100
            }
    })
    const emit = defineEmits(['update:num'])
    const btn = ()=>{
            emit('update:num',200);
    }

兄弟组件之间的传值

1》下载安装

        npm install mitt -S

2》plugins/Bus.js

        import mitt from 'mitt';
        const emitter = mitt();
        export default emitter;

3》A组件

        emitter.emit('fn',str);

4》B组件

        emitter.on('fn',e=>{
                s.value = e.value;
        })

插槽

匿名插槽

父:
    <A>
        这是xxxxx数据
        这是yyyyy数据
    </A>

子:
    <header>
        <div>头部</div>
        <slot></slot>
    </header>

    <footer>
        <div>底部</div>
        <slot></slot>
    </footer>

具名插槽

父:
    <A>
        <template v-slot:xxx>
                这是xxxxx数据
        </template>

        <template v-slot:yyy>
                这是yyyyy数据
        </template>
    </A>

    ***简写:<template #xxx>
子:
    <header>
        <div>头部</div>
        <slot name='xxx'></slot>
        <slot name='yyy'></slot>
    </header>

    <footer>
        <div>底部</div>
        <slot name='xxx'></slot>
    </footer>

作用域插槽

父:
    <template v-slot='{data}'>
        {{ data.name }} --> {{ data.age }}
    </template>

    简写:<template #default='{data}'>
子:
    <div v-for='item in list' :key='item.id'>
        <slot :data='item'></slot>
    </div>

动态插槽: 说白了就是通过数据进行切换

父:

    <template #[xxx]>
            这是xxxxx数据
    </template>

    <script setup>
    let xxx = ref('xxx');
    </script>

Teleport : 传送

<teleport to='#container'></teleport>

<teleport to='.main'></teleport>

<teleport to='body'></teleport>

***必须传送到有这个dom的内容【顺序】

动态组件

<component :is="动态去切换组件"></component>

异步组件

***提升性能

vueuse : vueuse.org/core/useint…

使用场景1

组件按需引入:当用户访问到了组件再去加载该组件

    <template>
            <div ref='target'>
                    <C v-if='targetIsVisible'></C>
            </div>
    </template>

    <script setup>
    import { useIntersectionObserver } from '@vueuse/core'

    const C = defineAsyncComponent(() =>
      import('../components/C.vue')
    )

    const target = ref(null);
    const targetIsVisible = ref(false);

    const { stop } = useIntersectionObserver(
      target,
      ([{ isIntersecting }]) => {
            if( isIntersecting ) {
                    targetIsVisible.value = isIntersecting
            }
      },
    )
    </script>

使用场景2

<Suspense>
    <template #default>
            <A></A>
    </template>
    <template #fallback>
            加载中...
    </template>
</Suspense>

<script setup>
    const A = defineAsyncComponent(() =>
    import('../components/A.vue')
    )
</script>

打包分包处理

npm run build打包完成后,异步组件有单独的js文件,是从主体js分包出来的

Mixin : 混入

是什么:来分发 Vue 组件中的可复用功能

setup写法

mixin.js
    import { ref } from 'vue'
    export default function(){

        let num = ref(1);
        let fav = ref(false);

        let favBtn = ()=>{
            num.value += 1;
            fav.value = true;
            setTimeout(()=>{
                    fav.value = false;
            },2000)
        }

        return {
            num,
            fav,
            favBtn
        }

    }
    
组件:
    <template>
        <div>
            <h1>A组件</h1>
            {{ num }}
            <button @click='favBtn'>
                    {{ fav ? '收藏中...' : '收藏' }}
            </button>
        </div>
    </template>

    <script setup>
        import mixin from '../mixins/mixin.js'
        let { num , fav , favBtn } = mixin();
    </script>

选项式api写法

mixin:
    export const fav = {
        data () {
            return {
                num:10
            }
        },
        methods:{
            favBtn( params ){
                this.num += params;
            }
        }
    }

组件:
    <template>
        <div>
            <h1>A组件</h1>
            {{ num }}
            <button @click='favBtn(1)'>按钮</button>
        </div>
    </template>

    <script type="text/javascript">
    import { fav } from '../mixins/mixin.js'
    export default{
        data () {
            return {
                str:'你好'
            }
        },
        mixins:[fav]
    }
    </script>

Provide / Inject ==> 依赖注入

提供:
    <script setup>
        provide('changeNum', num );
    </script>

注入:
    <template>
        <div>
            <h1>B组件</h1>
            {{ bNum }}
        </div>
    </template>

    <script setup>
        const bNum = inject('changeNum');
    </script>

Vuex

state: let num = computed( ()=> store.state.num );

getters: let total = computed( ()=> store.getters.total );

mutations: store.commit('xxx')

actions: store.dispatch( 'xxx' )

modules:

和之前的版本使用一样

Vuex持久化存储【插件】

1. npm i vuex-persistedstate -S

2. import persistedState from 'vuex-persistedstate'

3. export default createStore({
      modules: {
            user
      },
   plugins:[persistedState({
        key:'xiaoluxian',
        paths:['user']
   })]
});

Pinia

Vuex和pinia的区别

参考网址: github.com/vuejs/rfcs/…

  1. pinia没有mutations,只有:state、getters、actions
  2. pinia分模块不需要modules(之前vuex分模块需要modules)
  3. pinia体积更小(性能更好)
  4. pinia可以直接修改state数据

pinia使用

官方网址:pinia.vuejs.org/

具体使用:xuexiluxian.cn/blog/detail…

pinia持久化存储

参考链接:xuexiluxian.cn/blog/detail…

setup语法糖插件

解决import { ref , reactive ... } 引入的问题

下载安装 npm i unplugin-auto-import -D

在vite.config.js中进行配置

import vue from '@vitejs/plugin-vue';
//引入插件
import AutoImport from 'unplugin-auto-import/vite';

const path = require('path');

export default defineConfig({
  plugins: [
        vue(),
        AutoImport({
                imports:['vue','vue-router']
        })
  ],
  resolve: {
    // 配置路径别名
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});