提前条件:安装了16.0或更高版本的Node.js,可使用node -v查看版本。
创建一个Vue应用:npm init vue@latest。
在js中加入setup:表示允许在script中直接编写组合式API,mount用于设置挂载点。
组合式api
setup选项
是组合式api的入口,其生命周期早于beforeCreate。由于执行时机过早,在setup中无法获取this。
注意点:
- 在setup中定义的数据和函数,都需要通过return暴露出去,才能在模板或其他地方使用。
原生写法
1 2 3 4 5 6 7 8 9 10 11
| setup() { console.log(1); const message = 'hello Vue3'; const logMessage = () => { console.log(message); }; return { message, logMessage }; },
|
- 语法糖写法,在script标签中加入setup属性:
reactive() 对象类型
接收一个对象类型的数据,返回一个响应式的对象,类似v-bind的效果,使用时无需添加.value。例如:
1 2 3 4 5
| import { reactive } from 'vue'; const state = reactive({ count: 0, message: 'Hello' });
|
ref() 简单类型或者对象类型
本质是在原有数据基础上包了一层对象,底层借助reactive实现响应式。在脚本中访问数据需通过.value,在模板中则不需要。示例:
1 2 3
| import { ref } from 'vue'; const num = ref(10); const obj = ref({ name: 'Vue' });
|
computed
计算属性默认是只读的,若添加get和set属性,就可支持修改。示例:
1 2 3 4 5 6 7 8 9 10
| 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(深度侦听)。
1 2 3 4 5
| import { watch, ref } from 'vue'; const count3 = ref(0); watch(count3, (new1, old) => { console.log(new1, old); });
|
1 2 3 4 5
| const count3 = ref(0); const nickname = ref(''); watch([count3, nickname], (new1, old) => { console.log(new1, old); });
|
一进入页面就触发监听回调,写法如下:
1 2 3 4 5 6
| const userInfo = ref({}); watch(userInfo, (new1, old) => { console.log(new1); }, { immediate: true });
|
deep
默认watch进行的是简单监视,若要深度监听对象内部属性的变化,需设置deep: true。注意watch只能传递两个参数,但immediate和deep可以同时在配置对象中设置。
精确监听对象中的某个参数
1 2 3 4 5 6
| const userInfo = ref({ age: 20 }); watch(() => userInfo.value.age, (new1, old) => { console.log(new1, old); }, { deep: true });
|
生命周期api
(此处因未提供图片内容,无法详细阐述,可参考Vue官方文档查看具体生命周期钩子函数及执行顺序)
父子通讯
父传子
父组件传值方式与Vue2类似,子组件在setup中通过defineProps定义接收的属性。示例:
1 2 3 4 5 6 7 8 9 10 11 12
| // 父组件
import { ref } from 'vue'; const userInfo = ref({ age: 25 });
// 子组件
const props = defineProps(['message']); console.log(props.message);
|
子传父
1 2 3 4 5 6 7 8 9
|
import { ref } from 'vue'; const userInfo = ref({ age: 25 }); const setUser = (newValue) => { userInfo.value.age = newValue; };
|
1 2 3 4 5 6
| const emit = defineEmits(['changename']); const changename = () => { emit('changename', 30); };
|
- 触发事件前需先使用defineEmits编译器宏生成emit方法。
模板引用和defineExpose
vue2中,模板引用通过ref获取真实的dom对象或组件实例对象。
vue3中,先创建ref对象,再通过ref标识绑定到标签。
在语法糖setup中的属性和方法默认不开放,若要开放,需使用defineExpose指定开放组件。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { ref } from 'vue'; const myRef = ref(null); const myMethod = () => { console.log('This is an exposed method'); }; defineExpose({ myRef, myMethod });
This is a div
|
provide 和 inject
语法:顶层组件使用provide('key', 顶层中的数据)提供数据,底层组件通过const xxx = inject('key')获取数据。例如:
1 2 3 4 5 6 7 8 9 10 11
| // 顶层组件
import { provide } from 'vue'; provide('message', 'Hello from parent');
// 底层组件
import { inject } from 'vue'; const message = inject('message'); console.log(message);
|
pinia vuex的替代品
核心概念包括state、action、getter。
首先安装pinia:
然后进行全局注册:
1 2 3 4 5 6
| import { createApp } from 'vue'; import App from './App.vue'; import { createPinia } from 'pinia';
const pinia = createPinia(); createApp(App).use(pinia).mount('#app');
|
接着在自己的js文件中创建函数,注意要返回相关数据或函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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方法。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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方法。示例:
1 2 3 4 5
| 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提供的全局前置守卫函数,在每次路由跳转前执行。
1 2 3 4
| router.beforeEach((to, from, next)) // to: 即将要进入的目标路由对象,包含到哪里去的完整路由信息 // from: 当前导航正要离开的路由对象,包含从哪里来的完整路由信息 // next(): 控制路由跳转的函数,调用next()表示放行,继续进行路由跳转;调用next(路径)则进行拦截,跳转到指定路径
|
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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;
|
既希望保留原本的形参,又需要通过调用函数传参
通过箭头函数包装一层,例如:
1
| changeCount(value, item.goods_id, item.goods_sku_id)" :value="item.goods_num">
|
在上述代码中,@input绑定的事件处理函数使用箭头函数,既保留了input事件原本传递的value参数,又可以额外传递item.goods_id和item.goods_sku_id参数给changeCount函数。
跨模块操作
与页面中调用类似,使用commit('模块名/方法', [], {root: true})进行跨模块操作,{root: true}表示在根store中查找该mutation方法,而不是在当前模块内查找。
懒加载
将组件的导入方式从静态导入改为动态导入,实现组件的懒加载,提高应用加载性能。例如:
1 2 3 4 5 6
| // 静态导入 import Login from '@/views/login'; import Layout from '@/views/layout'; // 改为动态导入 const Login = () => import('@/views/login'); const Layout = () => import('@/views/layout');
|
Ts
安装TypeScript,全局安装命令:
1
| npm install -g typescript
|
TS中类和接口的区别:类不仅可以定义属性,还能包含方法,用于创建对象实例并封装数据和行为;接口主要用于定义对象的类型结构,只包含属性的定义,用于约束对象的形状,确保对象具有特定的属性和类型。
打包作用
将多个文件合成一个文件(可供直接上传或者浏览器能直接访问文件),通过打包可以优化代码,减少文件数量和大小,提高应用的加载性能。
命令:npm build。
默认情况下是放到服务器的根目录打开。如果希望双击运行就需要在vue.config中配置publicPath: '/',这样可以确保在本地运行打包后的文件时,资源路径能够正确解析。