vue3正式学习

提前条件:安装了16.0或更高版本的Node.js,可使用node -v查看版本。
创建一个Vue应用:npm init vue@latest
在js中加入setup:表示允许在script中直接编写组合式API,mount用于设置挂载点。

组合式api

setup选项

是组合式api的入口,其生命周期早于beforeCreate。由于执行时机过早,在setup中无法获取this
注意点:

  1. setup中定义的数据和函数,都需要通过return暴露出去,才能在模板或其他地方使用。
    • 原生写法
    setup() {
    console.log(1);
    const message = 'hello Vue3';
    const logMessage = () => {
    console.log(message);
    };
    return {
    message,
    logMessage
    };
    },
  2. 语法糖写法,在script标签中加入setup属性:
    <script setup>
    // 在此处直接编写代码,无需显式return,变量和函数会自动暴露给模板
    </script>

reactive() 对象类型

接收一个对象类型的数据,返回一个响应式的对象,类似v-bind的效果,使用时无需添加.value。例如:

import { reactive } from 'vue';
const state = reactive({
count: 0,
message: 'Hello'
});

ref() 简单类型或者对象类型

本质是在原有数据基础上包了一层对象,底层借助reactive实现响应式。在脚本中访问数据需通过.value,在模板中则不需要。示例:

import { ref } from 'vue';
const num = ref(10);
const obj = ref({ name: 'Vue' });

computed

计算属性默认是只读的,若添加getset属性,就可支持修改。示例:

import { computed } from 'vue';
const count = ref(0);
const doubleCount = computed({
get() {
return count.value * 2;
},
set(newValue) {
count.value = newValue / 2;
}
});

watch函数

用于监听一个或多个数据(ref对象 )的变化,数据变化时执行回调函数。有两个额外参数:immediate(立即执行)和deep(深度侦听)。

  • 监听单个数据
import { watch, ref } from 'vue';
const count3 = ref(0);
watch(count3, (new1, old) => {
console.log(new1, old);
});
  • 监听多个函数
const count3 = ref(0);
const nickname = ref('');
watch([count3, nickname], (new1, old) => {
console.log(new1, old);
});

Immediate

一进入页面就触发监听回调,写法如下:

const userInfo = ref({});
watch(userInfo, (new1, old) => {
console.log(new1);
}, {
immediate: true
});

deep

默认watch进行的是简单监视,若要深度监听对象内部属性的变化,需设置deep: true。注意watch只能传递两个参数,但immediatedeep可以同时在配置对象中设置。
精确监听对象中的某个参数

const userInfo = ref({ age: 20 });
watch(() => userInfo.value.age, (new1, old) => {
console.log(new1, old);
}, {
deep: true
});

生命周期api

(此处因未提供图片内容,无法详细阐述,可参考Vue官方文档查看具体生命周期钩子函数及执行顺序)

父子通讯

父传子

父组件传值方式与Vue2类似,子组件在setup中通过defineProps定义接收的属性。示例:

// 父组件
<template>
<Son :message="userInfo.age"></Son>
</template>
<script setup>
import { ref } from 'vue';
const userInfo = ref({ age: 25 });
</script>

// 子组件
<script setup>
const props = defineProps(['message']);
console.log(props.message);
</script>

子传父

  1. 父组件在子组件标签上通过@绑定事件:
<template>
<Son :message="userInfo.age" @changename="setUser"></Son>
</template>
<script setup>
import { ref } from 'vue';
const userInfo = ref({ age: 25 });
const setUser = (newValue) => {
userInfo.value.age = newValue;
};
</script>
  1. 子组件通过emit方法触发事件,支持传参:
<script setup>
const emit = defineEmits(['changename']);
const changename = () => {
emit('changename', 30);
};
</script>
  1. 触发事件前需先使用defineEmits编译器宏生成emit方法。

模板引用和defineExpose

vue2中,模板引用通过ref获取真实的dom对象或组件实例对象。
vue3中,先创建ref对象,再通过ref标识绑定到标签。
在语法糖setup中的属性和方法默认不开放,若要开放,需使用defineExpose指定开放组件。示例:

<script setup>
import { ref } from 'vue';
const myRef = ref(null);
const myMethod = () => {
console.log('This is an exposed method');
};
defineExpose({
myRef,
myMethod
});
</script>
<template>
<div ref="myRef">This is a div</div>
</template>

provide 和 inject

语法:顶层组件使用provide('key', 顶层中的数据)提供数据,底层组件通过const xxx = inject('key')获取数据。例如:

// 顶层组件
<script setup>
import { provide } from 'vue';
provide('message', 'Hello from parent');
</script>

// 底层组件
<script setup>
import { inject } from 'vue';
const message = inject('message');
console.log(message);
</script>

pinia vuex的替代品

核心概念包括stateactiongetter
首先安装pinia

npm install pinia

然后进行全局注册:

import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';

const pinia = createPinia();
createApp(App).use(pinia).mount('#app');

接着在自己的js文件中创建函数,注意要返回相关数据或函数:

import { defineStore } from 'pinia';
import { ref } from "vue";

export const UserCount = defineStore('counter', () => {
const count = ref(0);
const msg = "原神";
// 计算属性的写法
const xxx = computed(() => {
return count.value * 2;
});
return {
count,
msg,
xxx
};
});

action异步实现

与组件中获取异步数据的写法一致,且无需提交mutation方法。示例:

import { defineStore } from 'pinia';
import { ref } from 'vue';
import axios from 'axios';

export const useDataStore = defineStore('data', () => {
const channelList = ref([]);
const getList = async () => {
const { data: { data } } = await axios.get('http://geek.itheima.net/v1_0/channels');
channelList.value = data.channels;
console.log(data.channels);
};
return {
channelList,
getList
};
});

使用时导入该组件后直接调用方法即可。

注意点

若直接解构store中的数据,会变成普通数据而失去响应性。因此,若要解构,需使用storeToRefs方法。示例:

import { useDataStore } from './stores/data';
import { storeToRefs } from 'pinia';

const store = useDataStore();
const { channelList } = storeToRefs(store);

Pinia持久化插件

(此处未提及具体插件使用方法,可参考Pinia官方文档了解相关持久化插件及使用方式)

使用postcss插件实现项目vw适配

官网:vant2中的进阶用法
安装命令:npm install postcss-px-to-viewport@1.1.1 -D@后边是版本号,-D表示安装成开发依赖。安装完成后,需在项目的postcss配置文件中进行相应配置,以实现将px单位自动转换为vw单位,适配不同屏幕尺寸。(具体配置可参考插件官方文档)

进阶

全局前置守卫

router.beforeEach

这是Vue Router提供的全局前置守卫函数,在每次路由跳转前执行。

router.beforeEach((to, from, next))
// to: 即将要进入的目标路由对象,包含到哪里去的完整路由信息
// from: 当前导航正要离开的路由对象,包含从哪里来的完整路由信息
// next(): 控制路由跳转的函数,调用next()表示放行,继续进行路由跳转;调用next(路径)则进行拦截,跳转到指定路径

实例:

const authUrl = ['/pay', '/myorder']; // 配置需要权限的路由表
router.beforeEach((to, from, next) => {
if (!authUrl.includes(to.path)) { // 如果不在要权限的路由表内,直接放行
next();
return;
}
const token = store.getters.token; // 要权限则先判断token
console.log(token);
if (token) { // 有token放行
next();
} else {
next('/login'); // 没有token放行到/login
}
});
export default router;

既希望保留原本的形参,又需要通过调用函数传参

通过箭头函数包装一层,例如:

<CountBox @input="(value) => changeCount(value, item.goods_id, item.goods_sku_id)" :value="item.goods_num">

在上述代码中,@input绑定的事件处理函数使用箭头函数,既保留了input事件原本传递的value参数,又可以额外传递item.goods_iditem.goods_sku_id参数给changeCount函数。

跨模块操作

与页面中调用类似,使用commit('模块名/方法', [], {root: true})进行跨模块操作,{root: true}表示在根store中查找该mutation方法,而不是在当前模块内查找。

懒加载

将组件的导入方式从静态导入改为动态导入,实现组件的懒加载,提高应用加载性能。例如:

// 静态导入
import Login from '@/views/login';
import Layout from '@/views/layout';
// 改为动态导入
const Login = () => import('@/views/login');
const Layout = () => import('@/views/layout');

Ts

安装TypeScript,全局安装命令:

npm install -g typescript

TS中类和接口的区别:类不仅可以定义属性,还能包含方法,用于创建对象实例并封装数据和行为;接口主要用于定义对象的类型结构,只包含属性的定义,用于约束对象的形状,确保对象具有特定的属性和类型。

打包作用

将多个文件合成一个文件(可供直接上传或者浏览器能直接访问文件),通过打包可以优化代码,减少文件数量和大小,提高应用的加载性能。
命令:npm build
默认情况下是放到服务器的根目录打开。如果希望双击运行就需要在vue.config中配置publicPath: '/',这样可以确保在本地运行打包后的文件时,资源路径能够正确解析。