VUE3与VUE2的区别,以及迁移方案

2021-12-17  本文已影响0人  我叫Aliya但是被占用了

新特性

API

- 组合式 API setup

import { ref, toRefs, readonly, watch, computed } from "vue";

export default {
  name: "demo",
  // 添加组合式API,在组件创建前执行所以,没有this
  setup(props) {
    // 使用 `toRefs` 创建对prop的 `user` property 的响应式引用
    const { user } = toRefs(props);

    // 将属性变为响应式的  ref(attr)
    const list = ref([]); // { value: [] }
    const GetData = async () => {
      list.value = await FetchList(props.user);
    };

    // 生命周期函数
    // on `mounted` call `GetData`
    onMounted(GetData);

    // 监听 user 的变化,重新请求 GetData
    watch(user, GetData);

    // 计算属性
    const keyword = ref("");
    const resList = computed(() => {
      return list.value.filter((item) => item.name.includes(keyword.value));
    });

    // 返回对象可以组件内this.调用
    return {
      list,
      GetData,
      keyword,
      resList,
    };
  },
};

如上所示,相同模块的功能被整合到了一起,下面把这部分功能提取到单独的文件 combined.js

// -- combined.js --
import { ref, toRefs, watch, computed } from "vue";

export default function Combined(user) {
  const list = ref([]); // { value: [] }
  const GetData = async () => {
    list.value = await FetchList(props.user);
  };

  const keyword = ref("");
  const resList = computed(() => {
    return list.value.filter((item) => item.name.includes(keyword.value));
  });

  onMounted(GetData);
  watch(user, GetData);

  return { GetData, keyword, resList };
}

// -- demo.vue --
import Combined from "./combined.js";
import { toRefs } from "vue";

export default {
  props: {
    user: { type: String },
  },
  setup(props) {
    const { user } = toRefs(props);
    const { GetData, keyword, resList } = Combined(user);
    return { GetData, keyword, resList };
  },
  methods: {
    Reset() {
      this.keyword = ""; // 自动触发搜索
    },
  },
};

- Teleport

<template>
  <button @click="modalOpen = true">点我弹框</button>

  <teleport to="body">
    <div v-if="modalOpen" class="modal">我在body下</div>
  </teleport>
</template>

<script>
export default {
  data() {
    return {
      modalOpen: false,
    };
  },
};
</script>

teleport 下内容将会挂载到 body 下

- 组件内根元素可以有多个,即片段

<template>
  <header>...</header>
  <!-- 调用处传入的属性绑定在这个标签上 -->
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>

- 组件事件定义和类型验证。emits 里定义的原生事件(比如 click)将替代原生事件的监听器

export default {
  props: {
    list: {
      type: Array,
    },
  },
  emits: {
    // 没有验证
    click: null,

    // 验证submit 事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true;
      } else {
        console.warn("Invalid submit event payload!");
        return false;
      }
    },
  },
  methods: {
    submitForm() {
      this.$emit("submit", { email, password });
    },
  },
};

- 多个 v-model 绑定

app.component("user-name", {
  props: {
    firstName: String,
    lastName: String,
  },
  template: `
    <input 
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">

    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `,
});
<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>

使用v-model:xxx传值,使用$emit('update:xxx')同步变更

- 自定义 v-model 修饰符

<my-component v-model:first-name.lowcase="bar"></my-component>
app.component("my-component", {
  props: {
    firstName: String,
    firstNameModifiers: {
      // 所有修饰符都在它里:{ lowcase: true }
      default: () => ({}),
    },
  },
  template: `
    <input type="text" 
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">
  `,
  created() {
    console.log(this.firstNameModifiers.lowcase); // true,可以根据此值做一些逻辑处理
  },
});

css <style scoped>

/* 深度选择器 类似/deep/,vue3不再支持/deep/ */
::v-deep(.foo) {
}
:deep(.foo) {
}

/* 插槽 */
::v-slotted(.foo) {
}
:slotted(.foo) {
}

/* 一次性全局规则 */
::v-global(.foo) {
}
:global(.foo) {
}

/* 尽量不使用 :deep .foo 这样的组合选择器*/

不兼容的变更

API

创建应用不再使用 new Vue

import { createApp } from "vue";
import MyApp from "./MyApp.vue";

const app = createApp(MyApp);
// 或链式调用 createApp(comp|page).mount('#app')

app.component("button-counter", {
  data: () => ({
    count: 0,
  }),
  template: '<button @click="count++">Clicked {{ count }} times.</button>',
});

app.directive("focus", {
  mounted: (el) => el.focus(),
});

app.use(VueRouter);

app.mount("#app");
2.x 全局 API 3.x 实例 API (app)
Vue.config app.config
Vue.config.productionTip removed
Vue.config.ignoredElements app.config.isCustomElement
Vue.use app.use
Vue.mixin app.mixin
Vue.component app.component
Vue.directive app.directive

.

this.$watch(
  () => this.c.d,
  (newVal, oldVal) => {
    // 做点什么
  }
)
// or
computed: {
  cd() { return this.c.d; }
},
watch{
  cd(newVal) {
    // do something
  }
}
上一篇 下一篇

猜你喜欢

热点阅读