Composition API + <script setup>
- 可以任意拆分组件的功能,抽离出独立的工具函数,大大提高了代码的可维护性。
- Composition API都是从 Vue 中单独引入,可以脱离对this 上下文的依赖。
<template>
<div>
<input type="text" v-model="title" @keydown.enter="addTodo" />
<button v-if="active < all" @click="clear">清理</button>
<ul v-if="todos.length">
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.done" />
<span :class="{ done: todo.done }"> {{ todo.title }}</span>
</li>
</ul>
<div v-else>暂无数据</div>
<div>
全选<input type="checkbox" v-model="allDone" />
<span> {{ active }} / {{ all }} </span>
</div>
</div>
</template>
<script>
import { ref, computed } from "vue";
function useTodos() {
let title = ref("");
let todos = ref([{ title: "学习Vue", done: false }]);
function addTodo() {
todos.value.push({
title: title.value,
done: false,
});
title.value = "";
}
function clear() {
todos.value = todos.value.filter((v) => !v.done);
}
let active = computed(() => {
return todos.value.filter((v) => !v.done).length;
});
let all = computed(() => todos.value.length);
let allDone = computed({
get: function () {
return active.value === 0;
},
set: function (value) {
todos.value.forEach((todo) => {
todo.done = value;
});
},
});
return { title, todos, addTodo, clear, active, all, allDone };
}
</script>
<script setup>
let { title, todos, addTodo, clear, active, all, allDone } = useTodos();
</script>
style标签内使用js变量
- 在样式中可以使用v-bind绑定script中声明的js变量
<template>
<h1 @click="add">点击变色</h1>
</template>
<script setup>
import { ref } from 'vue'
let color = ref('red')
const add = () =>{
color.value = Math.random() > 0.5? 'blue': 'red'
}
</script>
<style>
h1 {
color: v-bind(color);
}
</style>
各种拦截方式对比(后续补充)
- Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理。
watchEffect与watch监听的区别
- watchEffect 不需要指定监听的属性,他会在初始化的时候就执行一次自动收集依赖,只要我们回调中引用到了响应式的属性,那么当这些属性变更的时候,这个回调都会执行,而 watch 只能监听指定的属性而做出变更(v3开始可以同时指定多个)。
- 就是 watch 可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的。
- watchEffect如果存在的话,在组件初始化的时候就会执行一次用以收集依赖(与computed同理),而后收集到的依赖发生变化,这个回调才会再次执行,而 watch 不需要,因为他一开始就指定了依赖
和本地存储配合一起保存数据
<template>
<div>
<input type="text" v-model="title" @keydown.enter="addTodo" />
<ul v-if="todos.length">
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.done" />
<span :class="{ done: todo.done }"> {{ todo.title }}</span>
</li>
</ul>
</div>
</template>
<script>
import { ref, watchEffect } from "vue";
const useStorage = (name, value=[]) => {
value = localStorage.getItem(name) ? JSON.parse(localStorage.getItem(name)) : value;
let data = ref(value)
watchEffect(()=>{
localStorage.setItem(name,JSON.stringify(data.value))
})
return data
}
function useTodos() {
let title = ref("");
let todos = useStorage('todos',[{ title: "学习Vue", done: false }]);
function addTodo() {
todos.value.push({
title: title.value,
done: false,
});
title.value = "";
}
return { title, todos, addTodo };
}
</script>
<script setup>
let { title, todos, addTodo } = useTodos();
</script>
v-model更改
vue3中,默认情况下,组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。而vue2中是使用value作为prop
jsx支持
需要安装@vitejs/plugin-vue-jsx插件来支持jsx转化为createVNode 函数,从而得到jsx的虚拟dom。
npm install @vitejs/plugin-vue-jsx -D
// vue.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(),vueJsx()]
})
template和jsx的区别
- template 的语法是固定的,只有 v-if、v-for 等等语法。也就是说,template 遇见条件渲染就是要固定的选择用 v-if。我们按照这种固定格式的语法书写,这样 Vue 在编译层面就可以很方便地去做静态标记的优化。
- 而 JSX 只是 h 函数的一个语法糖,本质就是 JavaScript,想实现条件渲染可以用 if else,也可以用三元表达式,还可以用任意合法的 JavaScript 语法。也就是说,JSX 可以支持更动态的需求。而 template 则因为语法限制原因,不能够像 JSX 那样可以支持更动态的需求。这是 JSX 相比于 template 的一个优势。
- JSX 相比于 template 还有一个优势,是可以在一个文件内返回多个组件。
- 相比于我们自己去写 h 函数,在 template 解析的结果中,有以下几个性能优化的方面:
- 静态的标签和属性会放在 _hoisted 变量中,并且放在 render 函数之外。这样,重复执行 render 的时候,代码里的纯静态的标签,就不需要进行额外地计算,并且静态标签在虚拟 DOM 计算的时候,会直接越过 Diff 过程。
- @click 函数增加了一个 cache 缓存层,这样实现出来的效果也是和静态提升类似,尽可能高效地利用缓存。
- 动态属性会打标签与静态属性区分出来,因而存在使用一个数字去标记标签的动态情况。比如在 p 标签上,使用 8 这个数字标记当前标签时,只有 props 是动态的。而在虚拟 DOM 计算 Diff 的过程中,可以忽略掉 class 和文本的计算,这也是 Vue 3 的虚拟 DOM 能够比 Vue 2 快的一个重要原因。
- 在 template 和 JSX 这两者的选择问题上,只是选择框架时角度不同而已。我们实现业务需求的时候,也是优先使用 template,动态性要求较高的组件使用 JSX 实现,尽可能地利用 Vue 本身的性能优化。
vite环境变量
- 客户端源码中环境变量的读取与webpack有很大差别,可以根据官方文档来进行配置。
- 只有VITE_为前缀的变量才会暴露给客户端源码,当然可以通过envPrefix自定义前缀。
- vite.config.js的环境变量获取 process.env只能获取到
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx';
import { viteMockServe } from 'vite-plugin-mock'
export default ({mode}) => {
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
const localEnabled: boolean = (process.env.USE_MOCK as unknown as boolean) || true;
const prodEnabled: boolean = (process.env.USE_CHUNK_MOCK as unknown as boolean) || false;
return defineConfig({
plugins: [vue(),vueJsx(),
viteMockServe({
// ↓解析根目录下的mock文件夹
mockPath: "mock",
localEnabled: localEnabled, // 开发打包开关
prodEnabled: prodEnabled, // 生产打包开关
supportTs: true, // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件。
watchFiles: true, // 监视文件更改
}),],
resolve: {
alias: {
'@/': new URL('./src/', import.meta.url).pathname
}
},
})
}
mock配置
- vite.config.js配置见上面例子
- mock.js配置
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/api/getUserInfo',
method: 'post',
response: () => {
return {
code: 200,
data: {
nickname: '@cname',
age: '@integer(10-100)',
uid: '@id',
url: '@image',
city: '@city',
country: '@county(true)',
province: '@province',
mobile_phone: '@phone',
email: '@email',
region: '@region',
menus: [
{
menu_name: '一级导航',
id: '@id',
code: 'Nav1',
children: [
{
code: 'about',
menu_url: 'views/about',
access_permissions: '["about"]',
children: [],
menu_name: '测试1',
id: '@id'
},
{
code: 'home',
menu_url: 'views/home',
access_permissions: '["home"]',
children: [],
menu_name: '测试2',
id: '@id'
}
]
},
]
},
}
},
}
] as MockMethod[]