pnpm常用命令
pnpm i //pnpm安装
VUE3常见语法汇总
ref() //const count = ref(0) //count.value(访问值,包括对象要加.value) //任何类型的值,包括深层嵌套的对象或则JS内置数据结构
await nextTick() //要等待 DOM 更新完成后再执行额外的代码,可以使用 nextTick() 全局 API
reactive() //只能用于对象类型 (对象、数组和如 Map、Set 这样的集合类型)它不能持有如 string、number 或 boolean 这样的原始类型
模板语法1:<span>Message: {{ msg }}</span>
模板语法2(插入HTML):<span v-html="rawHtml"></span>
指令:<div v-bind:id="xd"></div> //常见指令 :id、:disable、:href
计算属性:(1)、import { ref, computed } from "vue"; (2)、const booksLength = computed(() => { return list.value.books.length > 0 ? "Yes" : "No"; }); (3)、 <span>{{ booksLength }}</span> // 不是以一个函数执行,不加()条件渲染:v-if、v-else、v-else-if、v-show
列表渲染:(1)、v-for(<li v-for="item in courseList">{{ item }}</li>) ;(2)、of(<li v-for="item of courseList">{{ item }}</li>)
#v-if和v-for是不推荐一起使用在同一个标签
事件监听:v-on:click="handler" 或则 @click="handler"
侦听器:watch(我们需要在状态变化时执行一些“副作用:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态)
侦听器:watchEffect()
onMounted:是一个生命周期钩子(生命周期函数),用于在组件实例被挂载到 DOM 上后执行代码。
onUnMounted://组件卸载之后
- 计算属性
为什么后面不加(),不是以一个函数执行
使用缓存,减少性能消耗
<script setup>
import { ref, computed } from "vue";
const list = ref({books: ["语文","数学","英语",],
});// 一个计算属性 ref
const booksLength = computed(() => {return list.value.books.length > 0 ? "Yes" : "No";
});
</script><template><p>拥有书籍的个数:</p><span>{{ booksLength }}</span>
</template>
- 可写计算属性
<script setup>
import { ref, computed } from "vue";
const firstName = ref("老");
const lastName = ref("王");const fullName = computed({// getterget() {return firstName.value + " " + lastName.value;},// setterset(newValue) {// 注意:我们这里使用的是解构赋值语法[firstName.value, lastName.value] = newValue.split(" ");},
});
// fullName.value = "范 冰冰";
</script><template><p>Has published books:</p><span>{{ fullName }}</span>
</template>
- 列表渲染
v-if和v-for是不推荐一起使用在同一个标签
当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高
这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名
对象的循环便利:便利对象的值、键、索引如下:
<script setup>
import { ref } from "vue";
const courseObject = ref({ front: "js", back: "java" });
</script><template><ul><li v-for="(value, key, index) in courseObject" v-if="!value">{{ value }} - {{ key }} -{{ index }}</li></ul>
</template>
- 事件修饰符
.stop //阻止事件的向上传播,阻止上层事件的发生
.prevent //阻止行为
.self //提交事件将不再重新加载页面
.capture //添加事件监听器时,使用 `capture` 捕获模式
.once //点击事件最多被触发一次
.passive //滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成
- 按键修饰符
.enter //enter键
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
- 系统按键修饰符
.ctrl
.alt
.shift
.meta
- 表单输入绑定
(1)、没使用vue时需要手动处理双向数据绑定
<input:value="text"@input="event => text = event.target.value"
>
(2)、v-model 指令帮我们简化了这一步骤
<input v-model="text">
- 侦听器
我们需要在状态变化时执行一些“副作用:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态
<script setup>
import { ref, watch } from "vue";const question = ref("");
const answer = ref("答案");
const loading = ref(false);// 可以直接侦听一个 ref
watch(question, (newQuestion) => {if (newQuestion.includes("?")) {loading.value = true;answer.value = "Thinking...";setTimeout(() => {answer.value = "是的";}, 1000);}
});
</script><template><p>提问问题<input v-model="question" :disabled="loading" /></p><p>{{ answer }}</p>
</template>
(1)即时回调侦听器
watch 默认是懒执行的:仅当数据源变化时,才会执行回调
watch(source,(newValue, oldValue) => {// 立即执行,且当 `source` 改变时再次执行},{ immediate: true }
)
(2)、一次性侦听器
源变化时触发一次 once: true
watch(source,(newValue, oldValue) => {// 当 `source` 变化时,仅触发一次},{ once: true }
)
watch vs. watchEffect
wathchEffect(() => {console.log('count is :${obj.value.count}');
})
watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
-
watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
-
watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。
-
组件上的ref
使用场景
1. 获取某个元素的位置、宽高
2. 子组件的内容
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'const child = ref(null)onMounted(() => {// child.value 是 <Child /> 组件的实例
})
</script><template><Child ref="child" />
</template>
- Vue3的所有生命周期函数流程
- Vue3生命周期函数整理总结
初始化阶段
- beforeCreate
- created
此阶段无法获取template里面DOM节点
<script setup>
/**组件加载前
/
</script>
挂载阶段
- onMounted(挂载之后)
- onBeforeMount
更新阶段
- onBeforeUpdate
- onUpdated
卸载阶段
- onBeforeUnmount
- onUnmounted(卸载之后)
第7集 Vue3单页面组件开发基础—组件定义+使用
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构
- 定义组件
<script setup>
import { ref } from 'vue'const count = ref(0)
</script><template><button @click="count++">You clicked me {{ count }} times.</button>
</template>
- 使用组件
要使用一个子组件,我们需要在父组件中导入它
<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script><template><h1>Here is a child component!</h1><ButtonCounter />
</template>
-
父子组件参数传递
defineProps 是一个仅
<script setup>
中可用的编译宏命令,并不需要显式地导入。
(1)、子组件定义
<script setup>
defineProps(['title'])
</script><template><h4>{{ title }}</h4>
</template>
(2)、Demo代码2
const props = defineProps({width: {type: String,default: "25%",required: false,},title: {type: String,default: "",required: false,},dialogVisible: {type: Boolean,default: false,required: true,},
});
- 父组件传递函数给子组件
// 子组件
defineEmits(["childClick"]);
@click="$emit('childClick')"// 父组件
@childClick="()=>{}"
第9集 Vue3单页面组件开发基础—插槽
- defineExpose
// 子组件
const xd=ref(0)
defineExpose({xd})// 父组件
const childRef=ref('')
<child-component ref='childRef' />
<span>{{childRef.xd}}<span/>
- 插槽 slot
// 子组件
<template><slot></slot>
</template>// 父组件
<child-component>小滴课堂
</<child-component>
第五章 深入掌握Vue3组件进阶内容
第1集 Vue3单页面组件开发进阶—组件注册+命名
- 全局注册
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import ChildComponent from "./ChildComponent.vue";const app = createApp(App);
app.component("ChildComponent", ChildComponent);
app.mount("#app");
全局注册虽然很方便,但有以下几个问题:
-
不必要的文件体积
全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”),如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。 -
难维护
全局注册在大型项目中使项目的依赖关系变得不那么明确,在父组件中使用子组件时,不太容易定位子组件的实现,和使用过多的全局变量一样,这可能会影响应用长期的可维护性
第2集 Vue3单页面组件开发进阶—props
- props声明
<script setup>
const props = defineProps(['xd'])console.log(props.xd)
</script>
<script setup>
defineProps({xd: String,name: String
})
</script>
defineProps中定义属性是单向数据流、如果需要更改可以再维护一个变量
const props = defineProps(['xd'])// 计数器只是将 props.xd 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.xd)
进一步处理/转换
const props = defineProps(['xd'])// 该 prop 变更时计算属性也会自动更新
const newXd = computed(() => props.xd+'老王')
第3集 Vue3单页面组件开发进阶—defineModel
- 双向数据绑定
// 子组件
<script setup>
const model = defineModel();
</script><template><h2>子组件</h2><input v-model="model" />
</template>
// 父组件
<script setup>
import ChildComponent from "./ChildComponent.vue";
import { ref } from "vue";const xd = ref("小滴课堂");
</script><template><h1>父组件</h1><span>{{ xd }}</span><ChildComponent v-model="xd"></ChildComponent>
</template>
- 多数据绑定
// 父组件
<ChildComponent v-model:xd="xd" v-model:aa="aa"></ChildComponent>// 子组件
const xd = defineModel("xd");
const aa = defineModel("aa");<input type="text" v-model="xd" />
<input type="text" v-model="aa" />
第4集 Vue3单页面组件开发进阶—依赖注入
- provide + inject
import { createApp } from 'vue'const app = createApp({})app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
<script setup>
import { inject } from 'vue'const message = inject('message')
</script>
- 和响应式数据配合
<!-- 在供给方组件内 -->
<script setup>
import { provide, ref } from 'vue'const xd = ref('小滴课堂')function updateXd() {xd.value = 'xdclass.net'
}provide('xd', {xd,updateXd
})
</script>
<!-- 在注入方组件 -->
<script setup>
import { inject } from 'vue'const { xd, updateXd } = inject('xd')
</script><template><button @click="updateXd">{{ xd }}</button>
</template>
第5集 Vue3单页面组件开发进阶—KeepAlive
概念:KeepAlive 是一个内置组件,它的功能是在多个组件间动态切换时,缓存被移除的组件实例。
<script setup>
import ChildComponent1 from "./ChildComponent1.vue";
import ChildComponent2 from "./ChildComponent2.vue";
import { ref } from "vue";
const xd = ref(true);
</script>
<template><h1>父组件</h1><button @click="() => (xd = !xd)">切换组件</button><KeepAlive><ChildComponent1 v-if="xd" /></KeepAlive><ChildComponent2 v-if="!xd" />
</template>
<script setup>
import { ref } from "vue";
const count = ref(0);
</script><template><h2>子组件1</h2><span>count:{{ count }}</span><button @click="count++">+</button>
</template>
第六章 实现单页面应用Vue3规模化的路由使用—Vue Router
第1集 Vue3单页面实现规模化Vue Router基础—入门使用
- 安装
pnpm install vue-router@4 //@4:指定版本
- 使用
import { createRouter, createWebHashHistory } from "vue-router";import ChildComponent1 from "./ChildComponent1.vue";
import ChildComponent2 from "./ChildComponent2.vue";
const routes = [{ path: "/one", component: ChildComponent1 },{ path: "/two", component: ChildComponent2 },
];
const router = createRouter({history: createWebHashHistory(),routes,
});export default router;
<script setup>
import { ref } from "vue";const xd = ref(true);
</script>
<template><h1>父组件</h1><p><!-- 通过传递 `to` 来指定链接 --><router-link to="/one">去组件1</router-link> <br /><router-link to="/two">去组件2</router-link></p><div><!-- 路由出口 --><router-view></router-view></div>
</template>
第2集 Vue3单页面实现规模化Vue Router基础—嵌套路由+编程式导航
- 嵌套路由
import { createRouter, createWebHashHistory } from "vue-router";
import ChildComponent1 from "./ChildComponent1.vue";
import ChildComponent2 from "./ChildComponent2.vue";
import ChildComponent3 from "./ChildComponent3.vue";const routes = [{path: "/one",component: ChildComponent1,},{path: "/two",component: ChildComponent2,children: [{path: "aa",component: ChildComponent3,},],},
];const router = createRouter({history: createWebHashHistory(),routes,
});export default router;
- 编程式导航
<script setup>
import router from "./router.js";
const routerChange = (n) => {router.push(n);
};
</script>
<template><h1>父组件</h1><p><button @click="routerChange('/one')">打开组件1</button> <br /><button @click="routerChange('/two')">打开组件2</button><br /><button @click="routerChange('/two/aa')">打开组件3</button></p><div><router-view></router-view></div>
</template>
第3集 Vue3单页面实现规模化Vue Router基础—命名+重定向
- 命名+重定向
重定向:redirect
//router.js
import { createRouter, createWebHashHistory } from "vue-router";
import ChildComponent1 from "./ChildComponent1.vue";
import ChildComponent2 from "./ChildComponent2.vue";
import ChildComponent3 from "./ChildComponent3.vue";const routes = [{path: "/",redirect: "/one",},{path: "/one",name: "one",component: ChildComponent1,},{path: "/two",name: "two",component: ChildComponent2,children: [{path: "three",name: "three",component: ChildComponent3,},],},
];const router = createRouter({history: createWebHashHistory(),routes,
});export default router;
<script setup>
import router from "./router.js"
const routerChange = (n) => {\router.push({ name: n });
}
</script>
<template>
<button @click="routerChange(three)">打开组件3</button>
</template>
第4集 Vue3单页面实现规模化Vue Router基础—路由传参
- 传参
query(推荐方式)
//父组件
//Url传参
<router-link :to="/one?xd=小滴课堂&state=xdclass">打开组件2</router-link>//对象传参
<router-link:to="{ path: '/one', query: { xd: '小滴课堂', state: 'xdclass' } }">打开组件1</router-link
>
//子组件
import { useRoute } from 'vue-router'
const route = useRoute();
<span>{{route.query.xd }}</span>
<span>{{route.query.state}}</span>
- params
//父组件中通过名字的方式传参
<router-link :to="{ name: 'one', params: { xd: '小滴课堂' } }">打开组件1</router-link
>//router.js 配置params方式传参
path: "/one/:xd"//子组件获取参数
route.params.xd
-变程式导航传参
const routerChange = (n, obj) => {router.push({ path: n, query: obj });
};
第5集 Vue3单页面实现规模化Vue Router进阶—历史记录模式+导航守卫
- 不同的历史记录模式
- 哈希模式:createWebHashHistory() 推荐
- html5模式:createWebHistory()
- 导航守卫(可以做权限验证)
//router.js
router.beforeEach((to, from, next) => {if (to.meta.isAuth) {if (localStorage.getItem("token") === "1") {next();} else {alert("请先登录");}} else {next();}
});
第6集 Vue3单页面实现规模化Vue Router进阶—路由懒加载
- 路由懒加载
component: () => import("./ChildComponent1.vue"),
第七章 玩转Vue3拥有组合式API的状态管理库—Pinia
第1集 为什么使用Pinia?
- 为什么使用Pinia?
- Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态
- 如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 export const state = reactive({}) 来共享一个全局状态
- Devtools 支持
- 热更新
- 支持服务端渲染
export const useCounterStore = defineStore('counter', () => {const count = ref(0)function increment() {count.value++}return { count, increment }
})
- 对比Vuex
- 提供了一个更简单的 API,符合组合式 API 风格的 API
- 搭配 TypeScript 一起使用时有非常可靠的类型推断支持
第2集 Vue3跨组件共享状态Pinia—安装+使用示例
- 安装
pnpm i pinia@2
- 使用
(1)、引入pinia
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const pinia = createPinia()
const app = createApp(App)app.use(pinia)
app.mount('#app')
(2)、定义 defineStore
写法1(推荐方式):
export const useCounterStore = defineStore('counter', () => {const count = ref(0)function increment() {count.value++}return { count, increment }
})
写法2:
// stores/counter.js
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => {return { count: 0 }},// 也可以这样定义// state: () => ({ count: 0 })actions: {increment() {this.count++},},
})
(2)、使用
import {useCounterStore } from "./store/counter"
const counter=useCounterStore ();pinia数据:<span>{{ counter.count }}</span>
<button @click="counter.increment">加</botton>