# vue3 中 setup 语法

# 1. 说明

<script setup> 中定义的顶级变量都可以直接在模板中使用

# 2. 基础

# 2.1. props

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

  export interface Props {
    name?: string,
    hobby?: string[],
  }

  const props = withDefaults(defineProps<Props>(), {
    name: 'light',
    hobby: () => ['打乒乓球', '打篮球'],
  });
</script>

# 2.2. computed

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

const now = computed(() =>{ 
  return Date.now()
})
</script>

# 2.3. v-model

<input> 元素使用 v-model

<input v-model="searchText" />

<!-- 等价于 -->
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

<CustomInput> 组件使用 v-model:

<CustomInput v-model="searchText" />

<!-- 等价于 -->
<CustomInput
  :modelValue="searchText"
  @update:modelValue="(newValue) => { searchText = newValue; }"
/>

<CustomInput> 内部实现:

<template>
  <input :value="modelValue" @input="handleInput" />
</template>

<script setup>
defineProps(['modelValue']);

const emit = defineEmits(['update:modelValue']);

const handleInput = ($event) => {
  emit('update:modelValue', $event.target.value)
}
</script>

# 2.4. 多个 v-model 绑定

使用:

<CustomInput v-model:name="person.name" v-model:age="person.age" >

<CustomInput> 内部实现:

<template>
  <div></div>
</template>
<script setup>
  // 属性
  const props = defineProps({
    name: String,
    age: Number
  })

  // 事件
  const emit = defineEmits(['update:name', 'update:age']);

  emit('update:name', '李四');
  emit('update:age', 19);
</script>

# 2.5. 全局属性

说明:

  • 在 vue2 中使用 Vue.prototype.$http 挂载全局属性
  • 在 vue3 中使用 app.config.globalProperties.$http

示例:

  1. 配置:

    const app = createApp(App);
    
    app.config.globalProperties.$user = { name: '张三' };
    
  2. 在 template 中使用

    {{ $user.name }}
    
  3. 在 setup 中使用

    const currentInstance = getCurrentInstance();
    console.log( currentInstance.appContext.config.globalProperties.$user );
    
    // or
    const { proxy } = getCurrentInstance();
    console.log( proxy.$user );
    

# 3. router

# 3.1. 定义 router

示例:

import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),

  scrollBehavior() {
    // 始终滚动到顶部
    return { top: 0 };
  },
  
  routes: [
    // ...
  ],
});

export default router;

参考:

# 3.2. router 与 route

示例:

<script setup>
import { useRouter, useRoute } from 'vue-router'
import { watch } from 'vue'

const router = useRouter()
const route = useRoute()

watch(
  () => route.params.id,
  async (newId) => {
    await fetchUser(newId)
  }
)
</script>

# 3.3. keep-alive

示例:

<!-- vue 2  -->
<template>
   <keep-alive>
     <router-view v-if="$route.meta.keepAlive" />
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"/>
</template>

<!-- vue 3  -->
<template>
  <router-view v-slot="{ Component }">
    <keep-alive>
      <component :is="Component" v-if="$route.meta.isKeepAlive" />
    </keep-alive>
    <component :is="Component" v-if="!$route.meta.isKeepAlive" />
  </router-view>
</template>

参考:

# 4. vuex

# 4.1. 日志

说明:

  • 控制台打印 vuex 的实时快照

使用:

import { createStore, createLogger } from 'vuex';
import type { Plugin } from 'vuex';

let plugins: Plugin<any>[] = [];

if (process.env.NODE_ENV === 'development') {
  plugins = [
    createLogger(),
  ];
}

export default createStore({
  plugins,
  state: {},
  getters: {},
  mutations: {},
});

# 4.2. 持久化

说明:

  • 将 state 存入 sessionStorage / localStorage

安装:

npm i vuex-persistedstate 

# "vuex-persistedstate": "^4.1.0"

使用:

// vue 3
import { createStore } from 'vuex';
import createPersistedState from 'vuex-persistedstate'; 

export default createStore({
  plugins: {
    createPersistedState({
      storage: window.sessionStorage,
      paths: [
        'USER_INFO',
      ],
    })
  },

  state: {
    CURRENT_SLIDE_INDEX: -1,

    USER_INFO: {
      name: '张三',
      age: 18,
    },
  },
});

参考:

# 4.3. 注意

在 data() 中使用 vuex:

export default {
  data() {
    // data() 比 computed 先执行
    // this.userInfo 为 undefined
    const name = this.userInfo.name;

    // 但通过 this.$store 是可以取到值的
    const age = this.$store.state.userInfo.age;

    return {
      name,
      age,
    };
  },

  computed: {
    ...mapState(['userInfo']),
  }
}

# 5. 参考

本章目录