上个月刚好要开发一个全新项目,正好赶上尤雨溪发布了 vue3.0 正式版,就索性用vue3来开启新项目了,俗话说的好,在实践中学习才能学的快。
因为项目是个后台管理系统,不太需要考虑兼容的问题,默认都使用 chrome ,要兼容 IE 的现在还无法使用。 对于2.x版本来说,最大的缺点就是代码复用,一般是通过 mixin 来复用,但是会导致很多个 mixin 里的东西异常混乱,你不知道你的某个属性某个方法来自哪个 mixin 里,还有可能命名冲突。按照我们的习惯,最好是一个函数,我们传参数,返回我们需要的功能,这样才比较简洁。另一个改变我觉得就是抛弃了 Class 的使用,对于每个功能来说,我们就可以当成是一个函数来使用,避免了以前把所有东西绑定在 this 上,会给开发者带来额外的心智负担。
如果你喜欢 React Hooks 的写法,你也一定会喜欢 Vue 3 的 composition API 写法,它集合了 2.x 的响应式加上 React Hooks 的优点,但是两者还是存在很大的不同。
-
mutable 和 immutable, vue 3.0 里的 setup 仅执行一遍,而 React Function Component 每次渲染都会执行。如果你使用过 React Hooks,然后来开发 Vue 3.0,就会感觉到差异,react 是在每次渲染的时候都执行整个函数,因此当一个地方依赖另一个地方的时候,不需要你手动监听,而 Vue 3.0 则需要监听变化,后面会举例说明。
-
React Hooks 只能在最顶层使用,不能放在条件语句中,并且有严格的顺序,composition API 则不需要
下面说下 Vue3 使用过程中的一些注意点:
- reactive 和 ref,在 vue 2.x 里全放在 data 里,这两个方法都可以创建响应式变量,一般来说,复杂类型用 reactive,基本类型用 ref,但是实际使用过程中,有些场景复杂类型使用 ref 会更好点,ref API 创建的初衷是为了避免在需要简单类型的时候还要用 reactive 来包一层。
// 列表
// 2.x
list = []
this.list = [1, 2, 3]
// 3.x
list = reactive([])
//获取接口列表数据后无法直接 list = data
list.splice(0, list.length, ...data)
list = ref([])
list.value = data
// 对于详情来说 个人觉得使用 ref 更方便
detail = ref(null)
detail.value = data
- setup ,在vue 3里,把所有的变量申明和函数都写在了 setup 里,如果组织的不好,很容易写出面条式的代码,有人会觉得全部放在 setup 里不如 2.x 里分类组织,但个人觉得没什么不好,因为我们需要的就两个 变量和方法,setup 反而更直观的知道 return 里的是什么,不需要把所有东西都挂载到 this 上。setup 是没有 this 的,有两个参数
// props 是父组件的变量,context 是上下文
// props 是响应式的,不能够解构,可以使用 toRefs 来转换
setup(props, context) {
const { title } = toRefs(props)
const { attrs, slots, emit } = context
emit('fn', data) // 触发父组件事件
}
- provide inject 深层嵌套给子组件传值的话使用很方便,需要更新内部注入的值的时候,最好提供一个方法来改变,保证数据单项流动
// 父组件
const count = ref(1)
const change = val => count.value = val
provide('count', count)
provide('change', change)
// 子组件
const count = inject('count')
const change = inject('change')
- useXXX 这个算是 Vue 3 最重要的东西了,这不是API或者什么,是一种编程理念或者代码组织方式,通过这个可以实现代码复用,使代码更加清晰简洁,代码写的好不好就取决于用的怎么样。 举个例子,有一个列表,有name 和 value 两项,可以新增、删除、编辑
function useList(item, initData = []) {
const list = reactive(initData);
const currentKey = ref('');
/*
watch(initData, val => {
console.log(val);
console.log(...val);
console.log(val.value);
if (val) {
tableStructure.splice(0, tableStructure.length, ...val);
}
});
*/
const addLine = () => {
if (currentKey.value) {
alert('请先保存正在编辑的字段');
return;
}
const now = +new Date();
list.push({
key: now,
...item,
});
currentKey.value = now;
};
const saveItem = key => {
const l = list.filter(row => row.columnName === item.columnName);
if (l.length > 1) {
alert('字段名称重复');
return;
}
currentKey.value = '';
};
const editItem = key => {
if (currentKey.value) {
alert('请先保存正在编辑的字段');
return;
}
currentKey.value = key;
};
const deleteItem = key => {
const index = list.findIndex(item => item.key === key);
list.splice(index, 1);
// 删除当前正在编辑项
if (key === currentKey.value) {
currentKey.value = '';
}
};
// 调换顺序
const goUp = () => {
if (!currentKey.value) {
alert('请先点编辑按钮');
return;
}
const index = list.findIndex(item => item.key === currentKey.value);
if (index === 0) return;
list.splice(index - 1, 0, list.splice(index, 1)[0]);
};
const goDown = () => {
if (!currentKey.value) {
message.warn('请先点编辑按钮');
return;
}
const index = list.findIndex(item => item.key === currentKey.value);
if (index === list.length - 1) return;
list.splice(index + 1, 0, list.splice(index, 1)[0]);
};
// 提供方法改变值
const setList = data => {
list.splice(0, list.length, ...data);
};
const setKey = val => {
currentKey.value = val;
};
return {
setKey,
list,
currentKey,
addLine,
saveItem,
editItem,
deleteItem,
goUp,
goDown,
setList,
};
}
const {
list,
currentKey,
addLine,
saveItem,
editItem,
deleteItem,
goUp,
goDown,
setList,
setKey,
} = useList({ name: '', value: '' });
// useList({ name: '', value: '' }, list);
useList 有两个参数,一个是每一项初始化的值,另一个是初始数据,当列表为新建的时候,没问题,当如果有初始化数据的时候,比如第二个参数一开始为空,然后请求下接口,返回了一个初始化数据,再赋值给第二个参数。如果你用过 React Hooks,因为每次数据变化都会重新执行 useList,所以你不必管都会自动更新,但是 Vue里,只会执行一次,所以并不会主动更新列表。这时候有两种方法:
-
监听第二个参数的变化,然后更新列表,如上面代码的注释里所写
-
提供改变列表的方法,手动调用该方法
我更喜欢第二种做法,虽然第一种更“响应式”一点,但是第二种更清晰,和使用useXXX的优点一样,明确知道是哪里改变的。 总的来说,其实Vue 3的改动其实并不是很大,从 2.x 可以很快的过渡过来,相关配套 Vue Router 也没什么大问题,组件库使用的 ant design vue 2 的版本,现在在beta阶段,基本使用没什么大问题。最大的挑战是怎么组织代码避免面条式的臃肿代码,抽象和复用,这其实和 vue 3 本身无关。
实践是最好的学习方式, Have a try !