vue3.0从入门到实战

1,876 阅读2分钟

1. 开始

Vue3.0已经发布一段时间了,也是用一段时间了,感觉Vue3.0还是比较好用的,特别是Composition API用起来还是比较顺滑的,相对于Vue2.0的Options API还是比较清晰明了的,减少了来回切换的烦恼,提高了可读性和可维护性。

下面两张图可以清晰的对比两种API的区别,相信你看看完会果断选择Composition API😄

先来看下vue2.0的Options API

optionApi.png

在来看下vue3.0Composition API

compostionApi.png

comp.png

看完后,你是否还是有点迷惑,那我们再来看下一段实例。

先来看下Vue2写法:

export default {
  data() {
    return {
      list: [
        { title: 'VueJS', name: '学习Vue', id: 1 },
        { title: 'ReactJS', name: '学习React', id: 2 },
        { title: 'AngularJS', name: '学习Angular', id: 3 },
      ],
    };
  },
  methods: {
    addItem() {
      this.list.push({ title: 'NodeJs', name: '学习Node' });
    },
    deleteItem(id) {
      this.list = this.list.filter((item) => item.id !== id);
    },
  },
};

在来看下Vue3写法:

import { ref } from 'vue';

export default {
  setup() {
    const list = ref([
      { title: 'VueJS', name: '学习Vue', id: 1 },
      { title: 'ReactJS', name: '学习React', id: 2 },
      { title: 'AngularJS', name: '学习Angular', id: 3 },
    ]);
    const addItem = () => {
      list.value.push({ title: 'NodeJs', name: '学习Node' });
    };
    const deleteItem = (id) => {
      list.value = list.value.filter((item) => item.id !== id);
    };
    return {
      list, addItem, deleteItem,
    };
  },
};

对比Vue2语法,Vue3写起来简洁和方便,省去了我们来回切换的时间。

2. 创建项目

看到这个是不是有种跃跃欲试的感觉,下面我们先搭建开发环境。

我们可以使用 Vue CLI 或者 Vite2 搭建Vue3项目,

具体可以查看 手把手教你用vite2搭建Vue3.0项目 在这就不具体说了。

3. 使用

我们首先看下 Vue3中文 文档,了解Vue3基本语法,相对Vue2来说,还是有很大的改变的。

如果不想看文档也可以查看 体验Vue3.0

4. 开发优化

1. script setup

rfc.png

如果不想使用没使用一个变量都要return,那就可以使用setup开发,下面看下怎么使用

<script>
import { reactive } from 'vue';

export default {
  props: { msg: String },
  setup() {
    const state = reactive({ count: 0 });
    const addCount = () => {
      state.count++;
    };
    return {
      state, addCount,
    };
  },
};
</script>

使用script setup ↓↓

<script setup>
import { defineProps, reactive } from 'vue';
import Test from './Test.vue';

defineProps({
  msg: String,
});

const state = reactive({ count: 0 });
const addCount = () => {
  state.count++;
};
</script>

<script setup>rfcs7月份已经定稿了,vue3.2版本正式发布,想使用的小伙伴可以先体验一波。

更多使用方法:详情

2. style

image.png

export default {
  setup() {
    const state = reactive({
      fontSize: 20,
      color: 'red',
    });
    return {
      ...toRefs(state),
    };
  },
};
</script>

<style lang="scss" scoped>
.color-style{
  color: v-bind(color);
  font-size: v-bind(fontSize);
}
</style>

3. v-model 参数

先看下官网demo

<ChildComponent v-model:title="pageTitle" />

<!-- 是以下的简写: -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

v-bind-instead-of-sync.png

.sync修饰符已经弃用,如果想异步传值可以使用v-model:[params]

Vue2中一个组件v-model指定绑定一个值,Vue3中v-model可以绑定多个,这样对于我们同时动态获取多个值非常方便。

父组件:

# parent.vue

<template>
  <childCom v-model:value="parentValue" v-model:title="parentTitle"/>
</template>

<script>
import { ref } from 'vue';
import childCom from './childCom.vue';

export default {
  components: { childCom },
  setup() {
    const parentValue = ref('');
    const parentTitle = ref('');
    return { parentValue, parentTitle };
  },
};
</script>

<style lang="scss" scoped>

</style>

子组件:

# childCom.vue

<template>
  <input type="text" :value="value" @input="changeValue"> <br>
  <span>{{ text }}</span>
  <button @click="clickButton">
    plus
  </button>
</template>

<script>
import { reactive, toRefs } from 'vue';

export default {
  name: 'BaseInput',
  props: {
    value: {
      type: [String, Number],
      default: '',
    },
    text: {
      type: [String, Number], default: '测试',
    },
  },
  emits: ['update:value', 'input', 'update:text'],
  setup(props, context) {
    const state = reactive({
      textTest: '测试',
    });

    const changeValue = (e) => {
      context.emit('update:value', e.target.value);
      context.emit('input', e.target.value);
    };

    const clickButton = () => {
      context.emit('update:text', Math.random() * 100);
    };

    return { ...toRefs(state), changeValue, clickButton };
  },
};
</script>

<style>
</style>

4. Composition API

首先看下我们todos逻辑

<script>
import { reactive, toRefs } from 'vue';

export default {
  setup() {
    const state = reactive({
      list: [
        { title: 'VueJS', name: '学习Vue', id: 1 },
        { title: 'ReactJS', name: '学习React', id: 2 },
        { title: 'AngularJS', name: '学习Angular', id: 3 },
      ],
    });
    const addItem = () => {
      state.list.push({ title: 'NodeJs', name: '学习Node' });
    };
    const deleteItem = (id) => {
      state.list = state.list.filter((item) => item.id !== id);
    };
    const getLength = (list) => list.length;
    return {
      ...toRefs(state), addItem, deleteItem, getLength,
    };
  },
};
</script>

我们可以把逻辑或者其他的一些模块都拆出去,真正做到组合式API,方便以后我们的代码的维护,直接定位问题,找到模块修改就行,不会影响到其他的逻辑。

简单看一个实现:

// test.js

import { reactive, toRefs } from 'vue';

export default function () {
  const state = reactive({
    list: [
      { title: 'VueJS', name: '学习Vue', id: 1 },
      { title: 'ReactJS', name: '学习React', id: 2 },
      { title: 'AngularJS', name: '学习Angular', id: 3 },
    ],
  });
  const addItem = () => {
    state.list.push({ title: 'NodeJs', name: '学习Node' });
  };
  const deleteItem = (id) => {
    state.list = state.list.filter((item) => item.id !== id);
  };
  const getLength = (list) => list.length;
  return {
    state, addItem, deleteItem, getLength,
  };
}
<script>
import { toRefs } from 'vue';
import useTest from './test';

export default {
  setup() {
    const {
      state, addItem, deleteItem, getLength,
    } = useTest();
    return {
      ...toRefs(state), addItem, deleteItem, getLength,
    };
  },
};
</script>

这个类似Vue2的Mixins混入,不过他最大的好处就是可以清晰的看到我们所有引入的函数以及参数的名称和路径,避免使用相同的参数名污染的问题。清晰明了,真正做到按需加载所需要的函数,提高性能优化以及渲染速度。

5. 改动

1. $attrs

Vue2

在使用 inheritAttrs: false 时会产生副作用:

  • $attrs 中的 attribute 不再自动添加到根元素中,而是由开发者决定在哪添加
  • 但是 class 和 style 不属于 $attrs,仍然会应用到组件的根元素:

Vue3

在使用 inheritAttrs: false 的组件中,请确保样式仍然符合预期。如果你之前依赖 class 和 style 的特殊行为,那么可能会破坏一些视觉效果,因为这些 attribute 现在可能应用到了另一个元素。

$attrs 包含传递给组件的所有 attribute,包括 class 和 style

2. $listeners

$listeners 对象在Vue3中已被移除,现在监听事件监听器是$attrs的一部分

3. $children

$children 实例 property 已从 Vue 3.0 中移除, 如果获取元素,建议使用 $ref

4. 自定义指令

Vue2

  • bind - 指令绑定到元素后发生。只发生一次。
  • inserted - 元素插入父 DOM 后发生。
  • update - 当元素更新,但子元素尚未更新时,将调用此钩子。
  • componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
  • unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。

Vue3

  • created - 新的!在元素的 attribute 或事件侦听器应用之前调用。
  • bind → beforeMount
  • inserted → mounted
  • beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。
  • update → 移除!有太多的相似之处要更新,所以这是多余的,请改用 updated。
  • componentUpdated → updated
  • beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。
  • unbind -> unmounted
5. 过滤器

从 Vue 3.0 开始,过滤器已删除,不再支持。建议用计算属性或方法代替过滤器

也可以使用全局过滤器

如果在应用中全局注册了过滤器,那么在每个组件中用计算属性或方法调用来替换它可能就没那么方便了

// main.js
const app = createApp(App)

app.config.globalProperties.$filters = {
  currencyUSD(value) {
    return '$' + value
  }
}
<template>
  <h1>Bank Account Balance</h1>
  <p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>

注意:这种方式只能用于方法中,不可以在计算属性中使用,因为只有在单个组件的上下文中定义时才有意义。

其他的正在总结中,后续会持续更新。。。