Vue3 开发的避坑经验 对比Vue2

1. vue3 生命周期变化,使用script-setup模式

2.x生命周期3.x生命周期执行时间说明
beforeCreatesetup组件创建前执行
createdsetup组件创建后执行
beforeMountonBeforeMount组件挂载到节点上之前执行
mountedonMounted组件挂载完成后执行
beforeUpdateonBeforeUpdate组件更新之前执行
updatedonUpdated组件更新完成之后执行
beforeDestroyonBeforeUnmount组件卸载之前执行
destroyedonUnmounted组件卸载完成后执行
errorCapturedonErrorCaptured当捕获一个来自子孙组件的异常时激活钩子函数
<script setup lang="ts">
import { ref, onMounted } from "vue";
const count = ref<number>(0);

onMounted(() => {
  count.value = 1;
})
</script>

2. vue3 使用 vite 引用本地图片

  1. 使用import
<template>
  <img :src="xxx">
</template>

<script setup lang="ts">
import xxx from '@/assets/images/xxx.png';
</script>
  1. 在assets前面加一个src
<template>
  <img :src="xxxIcon">
</template>

<script setup lang="ts">
const xxxIcon = new URL(`/src/assets/images/xxx.png`, import.meta.url).href;
</script>

3. vue3 怎么使用this.$refs.xxx的使用

  1. 第一种方式
<template>
  <div ref="test">
    this is test
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
const test = ref(null);
onMounted(() => {
  console.log(test.value); // <div>this is test</div>
});
</script>
  1. 第二种方式
<template>
  <div v-for="(item, idx) in list" :ref="(el) => getCurRefs(el, `xxx_${idx}`)" @click="onClick(idx)">
    {{ item }}
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
const list = ref([1, 2, 3]);
const refArr = reactive({});
const getCurRefs = (el: any, id: string) => {
  refArr[id] = el;
};
const onClick = (idx) => {
  console.log(refArr[`xxx_${idx}`]);
};
</script>

4. vue3 组件传值

<script setup> 中必须使用 definePropsdefineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 <script setup> 中是直接可用的

子组件

<script setup lang="ts">
// 1.接收父组件传值
const props = defineProps<{
  foo: string,
  bar?: number,
}>();

// 2.想要设置默认值,通过 withDefaults 编译器宏
interface Props {
  msg?: string,
  labels?: string[],
};

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two'],
});

console.log(props.msg)  // hello

// 抛出事件
const emit = defineEmits<{
  (e: 'change', id: number): void,
  (e: 'update', value: string): void,
}>();

const click = () => {
  emit('change', 1);
  emit('update', 'abc');
};

const name = ref("xxxx");
defineExpose({ name }); // 显式暴露的数据,父组件才可以获取
</script>
<script setup>
// 非ts
const props = defineProps({
  foo: String,
})

const emit = defineEmits(['change', 'delete']);
</script>

父组件:

<template>
  <div>
    <child ref="child" :msg="'传递的值'" @change="change"/>
  </div>
</template>

<script setup lang="ts">
let child = ref(null);
console.log(child.value.name); //获取子组件中 name 的值为 xxxx

const change = (val: number) => {
  console.log(val);
};
</script>

5. vue3 的 ref 和 reactive

  • reactive() 函数接收一个普通的对象,返回出一个响应式对象。
  • ref() 函数可以根据给定的值来创建一个响应式的数据对象,返回值是一个对象,且只包含一个 .value 属性。
<script setup lang="ts">
import { ref, reactive } from 'vue';

const count = ref(0);
const arr = ref([]);
const user = reactive({
  id: 110,
  name: 'xxxx',
});

</script>
  1. 在 setup() 函数内,由 ref() 创建的响应式数据返回的是对象,所以需要用 .value 来访问;而在 setup() 函数外部则不需要 .value ,直接访问即可。
  2. 可以在 reactive 对象中访问 ref() 函数创建的响应式数据。
  3. 新的 ref() 会覆盖旧的 ref()。

6. vue3 的 computed

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

const count = ref(1);
const bigCount = computed(() => count.value + 1);

console.log(bigCount.value) // 输出 2
bigCount.value++ // error 不可写
</script>

7. vue3 的 watch

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

// 侦听一个 getter
const state = reactive({ count: 0 });
watch(() => state.count,
  (count, prevCount) => {
    console.log(count, prevCount);
  },
);

// 直接侦听一个 ref
const count = ref(0);
watch(count, (count, prevCount) => {
  console.log(count, prevCount);
});
</script>

8. 配置全局自定义参数

在 Vue2.x 中我们可以通过 Vue.prototype 添加全局属性 property。但是在 Vue3.x 中需要将 Vue.prototype 替换为 config.globalProperties 配置

// Vue2.x
Vue.prototype.$api = axios;
Vue.prototype.$eventBus = eventBus;

// Vue3.x
const app = createApp({});
app.config.globalProperties.$api = axios;
app.config.globalProperties.$eventBus = eventBus;

使用时需要先通过 vue 提供的 getCurrentInstance 方法获取实例对象:
警告:尽量不要使用 getCurrentInstance

<script setup lang="ts">
import { ref, onMounted, getCurrentInstance } from "vue";

onMounted(() => {
  const instance = <any>getCurrentInstance();
  const { $api, $eventBus } = instance.appContext.config.globalProperties;
  // do something
})
</script>

9. v-model 变化

当我们在使用 v-model 指令的时候,实际上 v-bindv-on 组合的简写,Vue2.x 和 Vue3.x 又存在差异。

  • Vue2.x
<script>
export default {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: {
      type: [Array, String],
      required: true,
    },
  },
  methods: {
    xxx() {
      this.$emit('change', 'test);
    },
  },
};
</script>
  • Vue3.x
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
const emit = defineEmits(['update:modelValue']);

let curValue = ref('');
let props = withDefaults(defineProps<{
    modelValue: string;
}>(), {
    modelValue: '',
})

onMounted(() => {
  // 先将 v-model 传入的 modelValue 保存
  curValue.value = props.modelValue;
})

watch(curValue, (newVal, oldVal) => {
  // 当 curValue 变化,则通过 emit 派发更新
  emit('update:modelValue', newVal);
})
</script>

10. router

  • Vue2.x
const { path, params, query } = this.$route;

this.$router.go(-1);
this.$router.push('/');
  • Vue3.x
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';

const { path, params, query } = useRoute();
const router = useRouter();
router.push('/');
</script>

11. env环境变量

  • Vue2.x
process.env.VUE_APP_BACKEND_DOMAIN
  • Vue3.x
  1. 使用方式一:
<script setup lang="ts">
const domain = import.meta.env.VITE_APP_BACKEND_DOMAIN;
</script>
  1. 使用方式二:
    vite.config.ts 使用方式为loadEnv(mode, process.cwd()).VITE_APP_SERVER_URL
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';

export default defineConfig(({ mode }) => {
  const VITE_APP_BACKEND_DOMAIN: string = loadEnv(mode, process.cwd()).VITE_APP_BACKEND_DOMAIN;

  return {
    plugins: [vue()],
    resolve: {
      //设置别名
      alias: {
        '@': resolve(__dirname, './src'),
      },
    },
    server: {
      port: 8080, //启动端口
      hmr: {
        host: '127.0.0.1',
        port: 8080,
      },
      // 设置 https 代理
      proxy: {
        '/api': {
          target: VITE_APP_BACKEND_DOMAIN, // 后端 api 地址
          changeOrigin: true,
          rewrite: (path: string) => path.replace(/^\/api/, ''),
        },
      },
    },
  };
});
  1. 使用方式三:如果想在文件中继续使用process.env,可以在vite.config.ts 中进行配置
import { defineConfig, loadEnv } from 'vite';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
   define: {
     'process.env': loadEnv(mode, process.cwd()),
  },
});

使用如下

const domain = process.env.VITE_APP_BACKEND_DOMAIN;
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值