Vue(十七):Vue3+ts 入门

Vue(十七):Vue3+ts 入门,第1张

Vue3 项目构建动态参数lodash计算属性侦听器 (watch、watchEffect)v-for在组件上使用 v-for复选框、选择框、lazy、numberAttribute在组件上使用 v-model插槽祖孙组件传值(provide、inject)动态组件异步组件(defineAsyncComponent、Suspense)模板引用ref生命周期setup、ref、toRef、toRefsMixinTeleportcustomRefreadonly、shallowReadonlyshallowReactive、shallowReftoRaw、markRaw路由vuex

项目构建 安装

$ npm init @vitejs/app app-name

选择环境

$ vue

选择脚本

$ vue-ts

动态参数

<template>
    <p :[attrName]="attrValue">{{ attrName }} : {{ attrValue }}p>
    <button @click="updateAttr">更新动态参数button>

    <div v-for="item in list" :ref="getChildElement">{{ item }}div>
template>

<script setup lang="ts">
import {ref, reactive} from "vue";

const attrName = ref('data-name');
const attrValue = ref('Lee');

const updateAttr = () => {
    attrName.value = 'data-id';
    attrValue.value = 'abc-def-ghi';
}

const list = reactive([1, 2, 3]);
const getChildElement = (el: HTMLElement) => console.log(el);
script>

<template>
    <button @[eventName]="eventFun">需要绑定事件类型button>
    <button @click="updateEvent">更新动态参数button>
template>

<script setup lang="ts">
import {ref} from "vue";

const eventName = ref('data-name');
let eventFun = (e: MouseEvent) => {
    console.log(e);
};

const updateEvent = () => {
    eventName.value = 'click';
}
script>
lodash

Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。 Lodash 的模块化方法 非常适用于:

遍历 array、object 和 string对值进行 *** 作和检测创建符合功能的函数

$ npm i lodash

$ npm i --dev @types/lodash

import _ from "lodash/index";

_([1, 2, 3, 4, 5, 6]).each(item => {
    console.log(item)
})
计算属性 单向
<template>
    <p>name : {{ name }}p>
    <p>fullName : <input type="text" v-model="fullName">p>

template>

<script setup lang="ts">
import _ from "lodash/index";
import {computed, reactive} from "vue";

const name = reactive({
    lastName: 'Lee',
    firstName: 'Prosper'
});

// 计算属性 --> 单向 (将计算好的数据插值到页面)
const fullName = computed(() => {
    return _(name).values().value().join('-');
})
script>
双向
<template>
    <p>name : {{ name }}p>
    <p>fullName : <input type="text" v-model="fullName">p>
template>

<script setup lang="ts">
import _ from "lodash/index";
import {computed, reactive} from "vue";

const name = reactive({
    lastName: 'Lee',
    firstName: 'Prosper'
});

// 计算属性 --> 双向 (修改页面内插值的同时改变定义的数据)
const fullName = computed({
    get() {
        return _(name).values().value().join('-');
    },
    set(value: string) {
        const names = _(value).split('-').value();
        name.lastName = names[0];
        name.firstName = names[1];
    }
})
script>
侦听器 (watch、watchEffect)

<template>
    <p>{{ data }}p>
    <p>msg : <input type="text" v-model="data.msg">p>
    <p>name : <input type="text" v-model="data.data.name">p>
template>

<script setup lang="ts">
// import _ from "lodash/index";
import {watch, reactive, watchEffect} from "vue";

const data = reactive({
    code: 200,
    data: {
        name: 'Lee',
        age: 25
    },
    msg: 'ok'
})

// 监听 数据对象
watch(data, value => {
    console.log('数据对象', value);
}, {deep: true, immediate: true})

// 监听 单个属性
watch(() => data.data.name, (newValue, oldValue) => {
    console.log('单个属性', newValue, oldValue);
}, {deep: true, immediate: true})

// 监听 多个属性
watch([() => data.msg, () => data.data.name], (newValues, oldValues) => {
    console.log('多个属性', newValues, oldValues);
}, {deep: true, immediate: true})

// 获取属性变化之后的值(刚方法会在初始化时默认执行)
watchEffect(() => {
    console.log(data.msg);
    console.log(data.data.name);
})
script>
v-for

<template>
    <ul>
        <li v-for="(value, name, index) in data">
            {{ index }} - {{ name }} - {{ value }}
        li>
    ul>
template>

<script setup lang="ts">
import {reactive} from "vue";

const data = reactive({
    name1: 'value1',
    name2: 'value2',
    name3: 'value3'
})
script>
在组件上使用 v-for

父组件 ---> 子组件 子组件 ---> 父组件

父组件

<template>
    <button @click="addRow(`Row-${Date.now()}`)">新增行button>
    <ul>
        <template v-for="(item, index) in items" :key="item.id">
            <Child :item="item.name" :index="index" @remove="removeRow(index)" @add="addRow"/>
            
            
        template>
        <hr>
        <Child v-for="(item, index) in items" :item="item.name" :index="index" :key="item.id"/>
    ul>
template>

<script setup lang="ts">
import _ from "lodash/index";
import {reactive} from "vue";

import Child from './Child.vue';

const items = reactive([
    {id: 'id-1', name: 'Lee'},
    {id: 'id-2', name: 'Tom'},
    {id: 'id-3', name: 'Lucy'}
]);

// 删除行
const removeRow = (index: number) => {
    _(items).splice(index, 1).value();
    console.log(items);
}
// 新增行
const addRow = (name: string) => {
    _(items).push({id: `id-${items.length}`, name}).value();
    console.log(items);
}
script>
子组件

<template>
    <li>
        <span>{{ index }} - {{ item }}span>
         
        <button @click="$emit('remove')">删除行button>
         
        <button @click="removeData">删除行button>
         
        <button @click="$emit('add', `Row-${Date.now()}`)">新增行button>
         
        <button @click="addData">新增行button>
    li>
template>

<script setup lang="ts">
import {defineProps, defineEmits} from "vue";

defineProps(['item', 'index']);

const emits = defineEmits(['remove', 'add']);

// 删除目标
const removeData = () => {
    emits('remove')
}

// 删除目标
const addData = () => {
    emits('add', `Row-${Date.now()}`)
}
script>

<style scoped>
span {
    display: inline-block;
    width: 200px;
}
style>
复选框、选择框、lazy、number

<template>
    <p>复选框p>
    <label>
        <input type="checkbox" v-model="toggle" true-value="yes" false-value="no" @change="checkboxChange"/>
        <span>复选框span>
    label>

    <p>选择框p>
    <select v-model="selected" @change="selectChange">
        <option v-for="item in list" :value="item">{{ item.name }}option>
    select>
    <span>{{ selected }}span>

    <p>lazy : 在调用change方法时改变数据p>
    <input v-model.lazy="msg" @change="textChange"/><span>{{ msg }}span>

    <p>number : 自动将用户的输入值转为数值类型p>
    <input v-model.number="num" @change="numberChange"/><span>{{ num }}span>
template>

<script setup lang="ts">
import _ from "lodash/index";
import {reactive, ref} from "vue";

// 复选框
const toggle = ref('yes');
const checkboxChange = () => {
    console.log(toggle.value)
}

// 选择框
const selected = ref({name: 'Tom'});
const list = reactive([{name: 'Lee'}, {name: 'Tom'}]);
const selectChange = () => {
    console.log(selected.value)
}

// lazy
const msg = ref('Hello Msg!!!');
const textChange = () => {
    console.log(msg)
}

// number
const num = ref(123);
const numberChange = () => {
    console.log(num.value)
}
script>
Attribute
// 父组件
<template>
    <Child data-msg="Hello" :data-status="activated"/>
    <button @click="activated = !activated">修改状态button>
template>
<script setup lang="ts">
import {ref} from "vue";
import Child from './Child.vue';

const activated = ref(true);
script>

// 子组件
<template>
    { data }} 报警告,提示你在msg外加上一层标签-->
    <p>{{ data }}p>
template>
<script setup lang="ts">
import {useAttrs} from "vue";

const data = useAttrs();
script>
在组件上使用 v-model
// 父组件
<template>
    <p>p>
    <input v-model="firstName">
    <input type="text" v-model="lastName">
    <hr>
    <Child v-model:first-name="firstName" v-model:last-name="lastName"/>
template>
<script setup lang="ts">
import {ref} from "vue";
import Child from './Child.vue';

const firstName = ref('Prosper');
const lastName = ref('Lee');
script>

// 子组件
<template>
    <p>p>
    <input :value="firstName" @input="$emit('update:firstName', $event.target.value)">
    <input type="text" :value="lastName" @input="$emit('update:lastName', $event.target.value)">
template>
<script setup lang="ts">
import {defineEmits, defineProps} from "vue";

defineProps(['firstName', 'lastName'])
defineEmits(['update:firstName', 'update:lastName']);
script>
插槽 默认插槽

<Child><p>默认插槽 : <span>ProsperLeespan>p>Child>


<template>
    <slot>slot>
template>
具名插槽

<template v-slot:default><p>具名插槽 : Hello Msg!!!p>template>
<template #default><p>具名插槽 : Hello Msg!!!p>template>


<template>
    <slot>slot>
template>

<template v-slot:slotName><p>具名插槽 : Hello Msg!!!p>template>
<template #slotName><p>具名插槽 : Hello Msg!!!p>template>


<template>
    <slot name="slotName">slot>
template>

<template>
    <button @click="changeSlotName">切换插槽button>
    <Child>
        <template #[dynamicSlotName]>Leetemplate>
    Child>
template>

<script setup lang="ts">
import Child from './Child.vue';
import {ref} from "vue";

const toggle = ref(true);
const dynamicSlotName = ref('slotNameA');

const changeSlotName = () => {
    toggle.value = !toggle.value;
    dynamicSlotName.value = toggle.value ? 'slotNameA' : 'slotNameB';
}
script>



<template>
    <p style="color: aqua;">
        <slot name="slotNameA">slot>
    p>
    <p style="color: red;">
        <slot name="slotNameB">slot>
    p>
template>
作用域插槽

<Child>
<template v-slot:default="scope">作用域插槽 : {{ scope.data }}template>
<template #default="scope">作用域插槽 : {{ scope.data }}template>
<template #default="{data}">作用域插槽 : {{ data }}template>
Child>


<template>
    <ul>
        <li v-for="( item, index ) in items">
            <slot :data="item">{{ index }} - {{item.name}}slot>
        li>
    ul>
template>
<script setup lang="ts">
import {reactive} from "vue";

const items = reactive([{name: 'Lee'}, {name: 'Tom'}]);
script>

<template>
    <Child>
        <template v-slot:slotName="scope">作用域插槽 : {{ scope.data }}template>
        <template #slotName="scope">作用域插槽 : {{ scope.data }}template>
        <template #slotName="{data}">作用域插槽 : {{ data }}template>
    Child>
template>


<template>
    <ul>
        <li v-for="( item, index ) in items">
            <slot name="slotName" :data="item">{{ index }} - {{item.name}}slot>
        li>
    ul>
template>

<script setup lang="ts">
import {reactive} from "vue";

const items = reactive([{name: 'Lee'}, {name: 'Tom'}]);
script>
祖孙组件传值(provide、inject)
// 祖组件
import Grandson from './components/Grandson.vue'
import {provide} from "vue";

provide('msg', 'Hello Msg!!!');

// 孙组件
import {inject} from "vue";

const msg = inject('msg');
console.log(msg);
动态组件

<template>
    <button @click="isKeepAlive = !isKeepAlive">是否缓存组件 {{ isKeepAlive }}button>

    <hr>

    <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{ tab }}button>
    <p>{{ currentTab }} - {{ currentTabComponent }}p>

    <hr>

    <keep-alive v-if="isKeepAlive">
        <component :is="currentTabComponent">component>
    keep-alive>
    <component v-else :is="currentTabComponent">component>
template>

<script lang="ts">
import {reactive, ref, computed, defineComponent} from "vue";
import Tab1 from './Tab1.vue';
import Tab2 from './Tab2.vue';
import Tab3 from './Tab3.vue';

export default defineComponent({
    components: {
        Tab1,
        Tab2,
        Tab3
    },
    setup() {
        // 是否缓存组件
        const isKeepAlive = ref(true);

        const currentTab = ref('Tab1');
        const tabs = reactive(['Tab1', 'Tab2', 'Tab3']);
        const currentTabComponent = computed(() => {
            return currentTab.value;
        })

        return {
            isKeepAlive,
            currentTab,
            tabs,
            currentTabComponent
        }
    }
})
script>
异步组件(defineAsyncComponent、Suspense)

<template>
    <button @click="isKeepAlive = !isKeepAlive">是否缓存组件 {{ isKeepAlive }}button>

    <hr>

    <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{ tab }}button>
    <p>{{ currentTab }} - {{ currentTabComponent }}p>

    <hr>

    <Suspense>
        <template #default>
            <keep-alive v-if="isKeepAlive">
                <component :is="currentTabComponent">component>
            keep-alive>
            <component v-else :is="currentTabComponent">component>
        template>
        <template #fallback>Loading···template>
    Suspense>
template>

<script lang="ts">
import {reactive, ref, computed, defineComponent, defineAsyncComponent} from "vue";

export default defineComponent({
    components: {
        Tab1: defineAsyncComponent(() => new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(import("./Tab1.vue"));
            }, 3000);
        })),
        Tab2: defineAsyncComponent(() => import("./Tab2.vue")),
        Tab3: defineAsyncComponent(() => import("./Tab3.vue")),
    },
    setup() {
        // 是否缓存组件
        const isKeepAlive = ref(true);

        const currentTab = ref("Tab1");
        const tabs = reactive(["Tab1", "Tab2", "Tab3"]);
        const currentTabComponent = computed(() => {
            return currentTab.value;
        });

        return {
            isKeepAlive,
            currentTab,
            tabs,
            currentTabComponent,
        };
    },
});
script>
模板引用

<template>
    <div ref="box">ProsperLeediv>
    <Child ref="child"/>
template>

<script setup lang="ts">
import {onMounted, ref} from "vue";
import Child from "./Child.vue";

const box = ref<HTMLElement | null>(null);
const child = ref<HTMLElement | null>(null);

onMounted(() => {
    console.log(box.value);
    console.log(child.value.$el);
});
script>
ref

使用ref定义变量是为了保持 JavaScript 中不同数据类型的行为统一,因为在 JavaScript 中,Number 或 String 等基本类型是通过值而非引用传递的,使用ref定义值实际上是创建了一个响应式引用。

const count = ref(0);
console.log(count.value);
生命周期

<template>
template>

<script lang="ts">
import {
    defineComponent,
    onBeforeMount,
    onMounted,
    onBeforeUpdate,
    onUpdated,
    onBeforeUnmount,
    onUnmounted,
    onErrorCaptured,
    onRenderTracked,
    onRenderTriggered,
    onActivated,
    onDeactivated,
} from "vue";

export default defineComponent({
    name: "Demo",
    setup() {

        console.log('setup')

        onBeforeMount(() => {
            console.log('%cHook inside setup ---> onBeforeMount', 'color: green;')
        })

        onMounted(() => {
            console.log('%cHook inside setup ---> mounted', 'color: green;')
        })

        onBeforeUpdate(() => {
            console.log('%cHook inside setup ---> onBeforeUpdate', 'color: green;')
        })

        onUpdated(() => {
            console.log('%cHook inside setup ---> onUpdated', 'color: green;')
        })

        onBeforeUnmount(() => {
            console.log('%cHook inside setup ---> onBeforeUnmount', 'color: green;')
        })

        onUnmounted(() => {
            console.log('%cHook inside setup ---> onUnmounted', 'color: green;')
        })

        onErrorCaptured(() => {
            console.log('%cHook inside setup ---> onErrorCaptured', 'color: green;')
        })

        onRenderTracked(() => {
            console.log('%cHook inside setup ---> onRenderTracked', 'color: green;')
        })

        onRenderTriggered(() => {
            console.log('%cHook inside setup ---> onRenderTriggered', 'color: green;')
        })

        onActivated(() => {
            console.log('%cHook inside setup ---> onActivated', 'color: green;')
        })

        onDeactivated(() => {
            console.log('%cHook inside setup ---> onDeactivated', 'color: green;')
        })

        return {};
    },
    beforeCreate() {
        console.log('选项式 API ---> beforeCreate');
    },
    created() {
        console.log('选项式 API ---> created');
    },
    beforeMount() {
        console.log('选项式 API ---> beforeMount')
    },
    mounted() {
        console.log('选项式 API ---> mounted')
    },
    beforeUpdate() {
        console.log('beforeUpdate')
    },
    updated() {
        console.log('选项式 API ---> updated')
    },
    beforeUnmount() {
        console.log('选项式 API ---> beforeUnmount')
    },
    unmounted() {
        console.log('选项式 API ---> unmounted')
    },
    errorCaptured() {
        console.log('选项式 API ---> errorCaptured')
    },
    renderTracked() {
        console.log('选项式 API ---> renderTracked')
    },
    renderTriggered() {
        console.log('选项式 API ---> renderTriggered')
    },
    activated() {
        console.log('选项式 API ---> activated')
    },
    deactivated() {
        console.log('选项式 API ---> deactivated')
    },

});
script>
setup、ref、toRef、toRefs setup —> props

<template>
    <Demo data-name="ProsperLee" :data-age="25"/>
    <hr>
    <Child data-name="Lee" :data-age="25"/>
template>

<script setup lang="ts">
import Demo from './components/Demo.vue';
import Child from './components/Child.vue';
script>


<template>
    <label>
        <span>【ref】span>
        <button @click="getRefData">refbutton>
        <br>
        <input type="text" v-model="dataName"> 
        <span>{{ dataName }}span>
    label>
    <hr>
    <label>
        <span>【toRef】span>
        <button @click="getToRefData">toRefbutton>
        <br>
        <input type="text" v-model="dataAge"> 
        <span>{{ dataAge }}span>
    label>
template>

<script lang="ts">
import {defineComponent, ref, toRef} from "vue";

export default defineComponent({
    name: 'Demo',
    props: {
        'data-name': {
            type: String,
            default: ''
        },
        'data-age': {
            type: Number,
            default: 0
        }
    },
    setup(props: any, context) {

        // 响应数据可以修改
        const dataName = ref(props["dataName"]);
        console.log('ref ---> dataName', dataName);
        const getRefData = () => console.log(dataName.value);

        // 只读数据不可修改
        // [Vue warn] Set operation on key "dataAge" failed: target is readonly.
        const dataAge = toRef(props, 'dataAge');
        console.log('toRef ---> dataAge', dataName);
        const getToRefData = () => console.log(dataAge.value);

        return {
            dataName,
            getRefData,
            dataAge,
            getToRefData,
        }
    },
})
script>


<template>
    <label>
        <span>【toRefs】span>
        <button @click="getToRefsData">toRefsbutton>
        <br>
        <input type="text" v-model="dataName"> 
        <input type="text" v-model="dataAge"> 
        <span>{{ dataName }}-{{ dataAge }} {{ data }}span>
    label>
template>

<script lang="ts">
import {defineComponent, toRefs} from "vue";

export default defineComponent({
    name: 'Child',
    props: {
        'data-name': {
            type: String,
            default: ''
        },
        'data-age': {
            type: Number,
            default: 0
        }
    },
    setup(props: any, context) {

        // 只读数据不可修改(将响应式对象转化为普通对象,每个对象都是ref)
        // [Vue warn] Set operation on key "dataName" failed: target is readonly.
        // [Vue warn] Set operation on key "dataAge" failed: target is readonly.
        const data = toRefs(props);
        console.log('toRefs ---> data', data);
        const getToRefsData = () => console.log(data.dataName.value, data.dataAge.value);

        return {
            data,
            ...data,
            getToRefsData,
        }
    },
})
script>
setup —> context

<template>
    <p>{{ data }}p>
    <button @click="evFun">emitbutton>
template>

<script lang="ts">
import {defineComponent} from "vue";

export default defineComponent({
    name: 'Demo',
    setup(props: any, context) {
        // Attribute (非响应式对象,等同于 $attrs)
        const data = context.attrs;

        // 插槽 (非响应式对象,等同于 $slots)
        console.log(context.slots)

        // 触发事件 (方法,等同于 $emit)
        const evFun = () => context.emit('eventName', 'ProsperLee');

        // 暴露公共 property (函数)
        console.log(context.expose)

        return {
            data,
            evFun,
        }
    },
})
script>
Mixin 全局引用
const mixin = {
    data() {
        const msg = ref('Hello');
        return {
            msg
        }
    },
    methods: {
        sayHi() {
            console.log('Hi');
        }
    },
    created() {
        (this as any).sayHi();
    }
}

createApp(App)
    .mixin(mixin)
    .mount('#app')
局部引入
import {ref} from "vue";

export default {
    data() {
        const msg = ref('Hello');
        return {
            msg
        }
    },
    methods: {
        sayHi() {
            console.log('Hi');
        }
    },
    created() {
        (this as any).sayHi();
    }
}

// 组件1
import {defineComponent} from "vue";
import Demo from './components/Demo.vue';
import mixin from "./mixins";

export default defineComponent({
    name: 'App',
    components: {
        Demo
    },
    mixins: [mixin],
})

// 组件2
import {defineComponent} from "vue";
import mixin from "../mixins";

export default defineComponent({
    name: 'Demo',
    mixins: [mixin],
})
Teleport

修改DOM所属父标签的位置

teleport

<div style="position:absolute;top: 100px;left: 100px;">
<span>Prosperspan>
<teleport to="body">
    <span>Leespan>
teleport>
div>
在同一目标上使用多个 teleport

<div id="modals">div>
<teleport to="#modals"><span>Prosperspan>teleport>
<teleport to=".modals"><span>Leespan>teleport>
customRef

自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。

它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。


<template>
    <input type="text" v-model="text">
    {{ text }}
template>

<script setup lang="ts">
import {customRef} from "vue";

const useDebouncedRef = (value: string, delay = 200) => {
    let timeout: number;
    return customRef((track, trigger) => {
        return {
            get() {
                track();
                return value;
            },
            set(newValue: string) {
                clearTimeout(timeout)
                timeout = setTimeout(() => {
                    value = newValue
                    trigger();
                }, delay)
            }
        }
    })
}
const text = useDebouncedRef('hello');
script>
readonly、shallowReadonly

<template>
    <p>深度只读p>
    <input type="text" v-model="data1.name">
    <input type="text" v-model="data1.data.msg">
    <p>{{ data1 }}p>

    <p>浅度只读p>
    <input type="text" v-model="data2.name">
    <input type="text" v-model="data2.data.msg">
    <p>{{ data2 }}p>
template>

<script setup lang="ts">
import {reactive, readonly, shallowReadonly} from "vue";

const obj = reactive({
    name: 'Lee',
    data: {
        msg: 'Hello Lee!!!'
    }
})
// 深度只读
const data1 = readonly(obj);
// 浅度只读
const data2 = shallowReadonly(obj);
script>
shallowReactive、shallowRef

<template>
    <p>浅度响应数据p>
    <button @click="update">修改数据button>
    <input type="text" v-model="data.name">
    <input type="text" v-model="data.data.msg">
    <p>{{ data }}p>
template>

<script setup lang="ts">
import {shallowReactive} from "vue";

// 创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
const data = shallowReactive({name: 'Lee', data: {msg: 'Hello Lee!!!'}});
script>

<template>
    <p>浅度响应数据p>
    <button @click="update">修改数据button>
    <input type="text" v-model="data.name">
    <input type="text" v-model="data.data.msg">
    <p>{{ data }}p>
template>

<script setup lang="ts">
import {shallowRef} from "vue";

// 创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的
const data = shallowRef({name: 'Lee', data: {msg: 'Hello Lee!!!'}});
script>
toRaw、markRaw
<template>
    <p>【toRaw】返回 reactive 或 readonly 代理的原始对象p>
    <input type="text" v-model="data1.name">
    <input type="text" v-model="data1.data.msg">
    {{ data1 }}
    <p>【markRaw】标记一个对象,使其永远不会转换为 proxy。返回对象本身p>
    <input type="text" v-model="data2.name">
    <input type="text" v-model="data2.data.msg">
    {{ data2 }}
template>

<script setup lang="ts">
import { reactive, toRaw, markRaw } from "vue";

const obj = reactive<any>({ name: "Lee", data: { msg: "Hello Lee!!!" } });

const data1 = toRaw(obj);

const data2 = reactive<any>({name: "Lee", data: markRaw({ msg: "Hello Lee!!!" })});
script>
路由

$ npm install vue-router@4

<template>
    <router-link to="/">Homerouter-link>
    <router-link to="/news">Newsrouter-link>
    <router-link to="/about">Aboutrouter-link>
    <router-view>router-view>
template>
import { createRouter, createWebHashHistory } from 'vue-router';

const routes = [
    { path: '/', component: () => import('../components/Home.vue') },
    { path: '/news', component: () => import('../components/News.vue') },
    { path: '/about', component: () => import('../components/About.vue') },
]

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

router.beforeEach((to, from, next) => {
    console.log(to, from);
    next();
})

export default router;
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App)
    .use(router)
    .mount('#app')
vuex

$ npm install vuex@next --save

<template>
    <button @click="add">Count : {{ $store.state.count }}button>
template>

<script setup lang="ts">
import store from "./store";

const add = () => {
    store.commit("increment");
};
script>
import { createStore } from 'vuex';

const store = createStore({
    state() {
        return {
            count: 0
        }
    },
    mutations: {
        increment(state: any) {
            state.count++
        }
    }
})

export default store;
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App)
    .use(router)
    .use(store)
    .mount('#app')

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940972.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存