Vue (读音 /vjuː/,类似于 view) 是一套 **构建用户界面 ** 的 渐进式框架。
所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点。
Vue2官网:https://v2.cn.vuejs.org/
1)从官网下载vue.js文件
2)在html文件中引入vue.js
3)创建vue实例
DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>demotitle>
head>
<body>
<div id="app">{{msg}}div>
<script src="vue.js">script>
<script>
new Vue({
el: "#app",
data: {
msg:"hello Vue"
}
})
script>
body>
html>
插值表达式是一种Vue的模板语法,我们可以用插值表达式渲染出Vue提供的数据或表达式的结果。
语法:
{{ xxx }}
{{title}}
{{nickName.toUpperCase()}}
{{age >= 18 ? '成年':'未成年'}}
{{obj.name}}
{{fn()}}
响应式简单理解就是数据变,视图对应变。
data中的数据, 最终会被添加到实例上
① 访问数据: “实例.属性名”
② 修改数据: “实例.属性名”= “值”

概念:指令(Directives)是 Vue 提供的带有 v- 前缀 的 特殊 标签属性。
vue 中的指令按照不同的用途可以分为如下 6 大类:
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下2 个:
1)v-text(类似innerText)
使用语法: hello,意思是将 uame 值渲染到 p 标签中。
类似 innerText,使用该语法,会覆盖 p 标签原有内容。
2)v-html(类似 innerHTML)
使用语法: hello,意思是将 intro 值渲染到 p 标签中
类似 innerHTML,使用该语法,会覆盖 p 标签原有内容。
类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。
示例:
<div id="app">
<h2>个人信息h2>
<p v-text="uname">姓名:p>
<p v-html="intro">简介:p>
div>
<script>
const app = new Vue({
el:'#app',
data:{
uname:'张三',
intro:'这是一个非常优秀的boy'
}
})
script>
条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:
1)v-show
2)v-if
示例:
<script src="vue.js">script>
<div id="app">
<div class="box" v-show="flag">我是v-show控制的盒子div>
<div class="box" v-if="flag">我是v-if控制的盒子div>
div>
<script>
const app = new Vue({
el: '#app',
data: {
flag: true
}
})
script>
3)v-else 和 v-else-if
示例:
<script src="vue.js">script>
<div id="app">
<p v-if="gender==1">性别:♂ 男p>
<p v-else>性别:♀ 女p>
<hr>
<p v-if="score>=90">成绩评定Ap>
<p v-else-if="score>=80">成绩评定Bp>
<p v-else-if="score>=70">成绩评定Cp>
<p v-else>成绩评定Dp>
div>
<script>
const app = new Vue({
el: '#app',
data: {
gender: 1,
score: 95
}
})
script>
使用Vue时,如需为DOM注册事件,及其的简单,语法如下:
v-on: 简写为 @示例一:内联语句
<div id="app">
<button @click="count--">-button>
<span>{{ count }}span>
<button v-on:click="count++">+button>
div>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100
}
})
script>
示例二:处理函数
<div id="app">
<button @click="handleClick">切换显示隐藏button>
<h1 v-show="isShow">hello Vueh1>
div>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
},
methods:{
handleClick(e){
this.isShow = !this.isShow;
console.log(e);
}
}
})
script>
注意:
事件处理函数应该写到一个跟data同级的配置项(methods)中
methods中的函数内部的this都指向Vue实例
如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象
如果传递了参数,则实参 $event 表示事件对象,固定用法。
示例:
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="" width="200px">
<img :src="imgUrl" :title="msg" alt="" width="200px">
div>
<script>
const app = new Vue({
el: '#app',
data: {
imgUrl: './1.png',
msg: 'hello Vue'
}
})
script>
所谓双向绑定就是数据改变后,呈现的页面结果会更新,页面结果更新后,数据也会随之而变。
作用: 给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
**语法:**v-model=“变量”
示例:
<div id="app">
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
div>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
})
script>
<template>
<div>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}label>
div>
template>
<script>
export default {
data() {
return {
checked: false
}
}
}
script>
原理:v-model本质上是一个语法糖。例如应用在输入框上,就是value属性 和 input事件 的合写
Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for 指令需要使用 (item, index) in arr 形式的特殊语法,其中:
此语法也可以遍历对象和数字
示例1:
<div id="app">
<div v-for="(value, key, index) in object">{{key}} : {{value}}div>
<p v-for="item in 10">{{item}}p>
div>
<script>
const app = new Vue({
el: '#app',
data: {
object:{
name: "obejct1",
age: "18",
gender: "male"
}
},
})
script>
v-for中的key属性作为唯一标识,便于Vue进行列表项的正确排序复用。
<div v-for="item in items" :key="item.id">
{{ item.name }}
div>
注意:
:key表示key的值是动态绑定的。
key 的值只能是字符串 或 数字类型
key 的值必须具有唯一性
推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)
修饰符(Modifiers)是一种特殊的后缀,用于指示Vue对某些绑定的DOM事件或属性绑定行为进行特别处理。它们通常以点(
.)开始,添加到指令后,用来执行一些特定的操作或行为调整。
事件修饰符允许我们处理DOM事件的细节,例如事件冒泡、事件捕获、事件修饰键等。一用的事件修饰符:
.stop - 调用event.stopPropagation(),阻止事件继续传播。
.prevent - 调用event.preventDefault(),阻止事件的默认行为。
.capture - 使用事件捕获模式添加事件监听器。
.once - 事件将只触发一次。
键盘事件修饰符用于监听键盘事件,使得只有在特定键被按下时才触发某个操作。例如:
.enter.delete(捕获“删除”和“退格”键).space.up.down修饰符可以串联,即可以在同一个指令上使用多个修饰符,例如:
<button @click.stop.prevent="doThat">点击我button>
上述代码同时使用了.stop和.prevent修饰符,既停止事件冒泡也阻止默认行为。
用于创建双向数据绑定的v-model指令也支持几个修饰符,来定制如何绑定和监听输入控件的值:
.lazy - 取代input事件监听更新,使用change事件。.number - 输入字符串转为有效的数字。.trim - 输入去除首尾空格。计算属性是一种特殊的属性,它可以根据依赖的数据动态计算出一个新的值。计算属性的值会被 Vue.js 缓存,只有当依赖的数据发生改变时,才会重新计算这个属性的值。
计算属性的特点:
示例:
<div id="app">
<div>a + b 的结果为:{{sum}}div>
div>
<script>
const app = new Vue({
el: '#app',
data: {
a: 10,
b: 20
},
computed: {
sum: function (){
return this.a + this.b;
}
}
})
script>
计算属性默认的简写,只能读取访问,不能 “修改”,如果要 “修改” 需要写计算属性的完整写法

示例:
<div id="app">
姓:<input type="text" v-model="firstName"> +
名:<input type="text" v-model="lastName"> =
{{ name }}<br><br>
<button @click="name='张飞'">改名卡button>
div>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: '刘',
lastName: '备'
},
computed: {
name: {
get: function () {
return this.firstName + this.lastName
},
set: function (newValue) {
this.firstName = newValue.charAt(0);
this.lastName = newValue.slice(1);
}
}
}
})
script>
作用:监视数据变化,执行一些业务逻辑或异步操作
1)简化语法:声明在data同级的配置项中
watch: {
// 该方法会在数据变化时,触发执行
数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}
简化写法示例:
<div id="app">
{{ count }}
<button @click="count++">count++button>
div>
<script>
const app = new Vue({
el: '#app',
data: {
count: 0,
},
watch: {
count: function (oldVal, newVal){
console.log(oldVal + "->" + newVal)
}
}
})
script>
2)完整语法示例:
{{ count }}
注意:
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
1.创建阶段:创建响应式数据
2.挂载阶段:渲染模板
3.更新阶段:修改数据,更新视图
4.销毁阶段:销毁Vue实例

以下是Vue的生命周期钩子:

示例:
<div id="app">
{{ count }}
<button @click="count++">count++button>
div>
<script>
const app = new Vue({
el: '#app',
data: {
count: 0,
},
beforeUpdate: function (){
console.log(this.count);
}
})
script>
Vue的工程化开发是指通过一系种工具和规范,将Vue的开发流程进行标准化、自动化,提高开发效率和项目质量。它包括了项目初始化、开发、构建、部署、测试等环节。
Vue的脚手架是Vue CLI,它是一个全局安装的命令行工具,提供了项目创建、开发和构建等功能。Vue CLI能够帮助开发者快速创建Vue项目,它预设了一些项目模板,包括了webpack、Babel、ESLint等开发工具的配置,让开发者可以专注于编写业务代码,而不需要花费大量时间去配置这些工具。
使用步骤:


组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。
好处:便于维护,利于复用 → 提升开发效率。

组件由三部分构成:
App.vue为整个应用最上层的组件,包裹所有普通小组件

特点:只能在注册的组件内使用
1)创建三个组件
Header:
我是头部组件
Main:
我是主体组件
Footer:
我是底部组件
2)引入组件并在局部注册
特点:全局注册的组件,在项目的任何组件中都能使用
在main.js中注册:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import MyComponent from './components/MyComponent.vue'
const app = createApp(App)
app.component('my-component', MyComponent)
app.use(router).mount('#app')
写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。
全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
<template>
<div class="base-one">
BaseOne
div>
template>
<script>
export default {
}
script>
<style scoped>
style>
原理:
最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。

baseCount.vue:
{{ count }}
App.vue:
组件通信,就是指组件与组件之间的数据传递
父组件通过 props 将数据传递给子组件
子组件利用 $emit 通知父组件修改更新

父向子传值步骤:
子向父传值步骤:
Son.vue:
我是Son组件
count = {{ count }}
App.vue:
我是APP组件
props完整写法:
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值, // 默认值
validator (value) {
// 自定义校验逻辑
return 是否通过校验
}
}
},
父组件 provide提供数据
子/孙组件 inject获取数据
父组件:
export default {
provide () {
return {
// 普通类型【非响应式】
color: this.color,
// 复杂类型【响应式】
userInfo: this.userInfo,
}
}
}
子/孙组件:
export default {
inject: ['color','userInfo'],
created () {
console.log(this.color, this.userInfo)
}
}
注意:
v-model其实就是 :value 和 @input事件的简写
子组件:
props: {
value: String
},
methods: {
handleChange (e) {
this.$emit('input', e.target.value)
}
}
父组件:
作用:可以实现 子组件 与 父组件数据 的 双向绑定,简化代码
本质:.sync修饰符 就是 :属性名 和 @update:属性名 合写
父组件:
//.sync写法
---------------------------------------
//完整写法
子组件:
props: {
visible: Boolean
},
this.$emit('update:visible', false)
ref是 Vue.js 中的一个特殊属性,可以用来绑定到渲染的 DOM 元素或子组件上。当ref和 HTML 元素一起使用时,ref的值将是该元素;当ref和组件一起使用时,ref的值将是组件实例。
$refs是一个对象,持有已注册过ref的所有 DOM 元素和组件实例。它可以在组件的方法中通过this.$refs来访问。
示例:
$nextTick用于在下一次 DOM 更新循环结束之后延迟执行一段代码。在 DOM 更新之后,基于新的 DOM 状态来执行一些操作时非常有用。
示例:
{{ message }}
内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,可以直接使用
自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令,每个指令都有自己各自独立的功能
示例一:局部注册
示例二:全局注册
main.js:
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
const app = createApp(App);
app.directive("color", (el, binding) => {
el.style.color = binding.value; // 获取指令的值
});
app.use(router).mount("#app");
app.vue:
蓝色
作用:让组件内部的一些 结构 支持 自定义
语法:
示例:
子组件:
友情提示
✖️
父组件:
是否确认删除?
封装组件时,可以为预留的 插槽提供后备内容(默认内容)。
示例:
友情提示
✖️
我是默认内容
当一个组件内有多处结构,需要外部传入标签进行定制时就需要给每个结构定义名字加以区分。
语法:
#示例:
子组件:
父组件:
友情提示
是否确认删除?
定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用
使用方式:
1)给 slot 标签, 以 添加属性的方式传值
2)所有添加的属性, 都会被收集到一个对象中
{ id: 3, msg: '测试文本' }
3)在template中, 通过 #插槽名= "obj" 接收,默认插槽名为 default
示例:
子组件:
序号
姓名
年纪
操作
{{ index }}
{{ item.name }}
{{ item.ages }}
父组件:
Vue路由是单页面应用的核心,所有的页面跳转都通过路由来完成。
Vue Router是路由管理器
配置路由:
// 引入 vue-router 的两个方法:createRouter 和 createWebHistory
import { createRouter, createWebHistory } from 'vue-router'
// 引入 HomeView 组件
import HomeView from '../views/HomeView.vue'
// 定义路由映射
const routes = [
{
// 当用户访问根路径(即 '/')时,将会渲染 HomeView 组件
path: '/home',
name: 'home',
component: HomeView
},
{
// 当用户访问 '/about' 路径时,将会渲染 AboutView 组件
// 这里使用了懒加载的方式来引入 AboutView 组件,即当路由被访问时才加载对应组件,可以提高首屏加载速度
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
}
]
// 创建 router 实例
const router = createRouter({
// 使用 HTML5 的 History 路由模式
history: createWebHistory(process.env.BASE_URL),
// 应用的路由映射
routes
})
// 导出 router 实例
export default router
其中路由模式:
App.vue:
我们可以通过在样式中添加.router-link-active来设置选中链接的样式,从而实现选中高亮的效果。例如,我们可以设置选中链接的颜色为蓝色:
<style scoped>
/* 其他样式 */
.router-link-active {
background-color: blue;
}
style>
.router-link-active是模糊匹配,只要路径中含有配置路由即可高亮(使用较多)。
.router-link-exact-active是精确匹配,路径必须与配置路由一致才可匹配。
在路由配置时使用linkActiveClass和linkExactActiveClass也可自己定义类目
const router = new VueRouter({
routes: [...],
linkActiveClass: 'active', // 配置模糊匹配的类名
linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
})
我们可以通过两种方式,在跳转的时候把所需要的参数传到其他页面中
1)查询参数传参
$router.query.参数名2)动态路由传参
配置动态路由:动态路由后面的参数可以随便起名,但要有语义
const router = new VueRouter({
routes: [
...,
{
path: '/search/:words',
component: Search
}
]
})
配置导航链接:to="/path/参数值"
对应页面组件接受参数:$route.params.参数名
示例一:查询参数传参
This is an about page
{{ $route.query.key }}
示例二:动态路由传参
router:
const routes = [
{
path: "/home",
name: "home",
component: HomeView,
},
{
path: "/about/:key",
name: "about",
component: () => import("../views/AboutView.vue"),
},
];
App.vue:
about.vue:
This is an about page
{{ $route.params.key }}
注意:
/search/:key 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符?
{
path: "/about/:key?",
name: "about",
component: () => import("../views/AboutView.vue"),
}
语法:{ path: 匹配路径, redirect: 重定向到的路径 }
示例:
const routes = [
{
path: "/",
redirect: "/home",
},
{
path: "/home",
name: "home",
component: HomeView,
},
{
path: "/about/:key",
name: "about",
component: () => import("../views/AboutView.vue"),
},
];
当路径找不到匹配时,需要给个提示页面
path: “*” (任意路径) – 前面不匹配就命中最后这个
import NotFind from '@/views/NotFind'
const router = new VueRouter({
routes: [
...
{ path: '*', component: NotFind } //最后一个
]
})
1)query传参跳转
//简单写法
this.$router.push('/路径?参数名1=参数值1&参数2=参数值2')
//完整写法
this.$router.push({
path: '/路径',
query: {
参数名1: '参数值1',
参数名2: '参数值2'
}
})
示例:
2)动态路由传参
//简单写法
this.$router.push('/路径/参数值')
//完整写法
this.$router.push({
path: '/路径/参数值'
})
Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息。
1)安装
安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。
yarn add vuex@3 或者 npm i vuex@3
2)新建 store/index.js 专门存放 vuex
为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js文件。 (和 router/index.js 类似)
3)创建仓库 store/index.js
// 导入 vue
import Vue from "vue";
// 导入 vuex
import Vuex from "vuex";
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex);
// 创建仓库 store
const store = new Vuex.Store();
// 导出仓库
export default store;
4)在 main.js 中导入挂载到 Vue 实例上
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
此刻起,就成功创建了一个空仓库
State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。
打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。
设置数据:
// 创建仓库 store
const store = new Vuex.Store({
// state 状态, 即数据, 类似于vue组件中的data,
// 区别:
// 1.data 是组件自己的数据,
// 2.state 中的数据整个vue项目的组件都能访问到
state: {
count: 101
}
})
获取数据语法:
获取 store:
1.Vue模板中获取 this.$store
2.js文件中获取 import 导入 store
模板中: {{ $store.state.xxx }}
组件逻辑中: this.$store.state.xxx
JS模块中: store.state.xxx
示例:
count1: {{ $store.state.count }}
count2: {{ count }}
mapState是辅助函数,帮助我们把store中的数据映射到 组件的计算属性中, 它属于一种方便的用法
用法:
1)导入mapState (mapState是vuex中的一个函数)
import { mapState } from 'vuex'
2)采用数组形式引入state属性
mapState(['count'])
上面代码类似于:
count () {
return this.$store.state.count
}
3)利用展开运算符将导出的状态映射给计算属性
computed: {
...mapState(['count'])
}
示例:
count1: {{ $store.state.count }}
count2: {{ count }}
在组件中无法直接修改store中的数据,需要借助mutation修改数据。
mutations是一个对象,对象中存放修改state的方法
1)在store.js中添加方法:
state: {
count: 0,
},
mutations: {
addCount1(state) {
state.count++;
},
addCount2(state, num) {
state.count += num;
},
}
2)调用方法:
count1: {{ $store.state.count }}
count2: {{ count }}
mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入
import { mapMutations } from 'vuex'
methods: {
...mapMutations(['addCount'])
}
上面代码的含义是将mutations的方法导入了methods中,等价于
methods: {
// commit(方法名, 载荷参数)
addCount () {
this.$store.commit('addCount')
}
}
此时,就可以直接通过this.addCount调用了
actions负责进行异步操作
1)添加actions方法
mutations: {
changeCount (state, newCount) {
state.count = newCount
}
}
actions: {
setAsyncCount (context, num) {
// 一秒后, 给一个数, 去修改 num
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
},
2)组件中通过dispatch调用方法
setAsyncCount () {
this.$store.dispatch('setAsyncCount', 666)
}
mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中
import { mapActions } from 'vuex'
methods: {
...mapActions(['changeCountAction'])
}
直接通过 this.方法 就可以调用
除了state之外,有时我们还需要从state中筛选出符合条件的一些数据,这些数据是依赖state的,此时会用到getters
例如,state中定义了list,为1-10的数组,
state: {
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它。
1)定义getters
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
filterList: state => state.list.filter(item => item > 5)
}
2)使用getters
原生方式:
{{ $store.getters.filterList }}
辅助函数:
computed: {
...mapGetters(['filterList'])
}
{{ filterList }}
如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护。由此,有了Vuex的模块化。

在store目录下创建一个module文件夹,定义两个模块 user 和 setting
user中管理用户的信息状态 userInfo modules/user.js
const state = {
userInfo: {
name: 'zs',
age: 18
}
}
const mutations = {}
const actions = {}
const getters = {}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
setting中管理项目应用的 主题色 theme,描述 desc, modules/setting.js
const state = {
theme: 'dark'
desc: '描述真呀真不错'
}
const mutations = {}
const actions = {}
const getters = {}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
在store/index.js文件中的modules配置项中,注册这两个模块
import user from './modules/user'
import setting from './modules/setting'
const store = new Vuex.Store({
modules:{
user,
setting
}
})
使用模块中的数据, 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.desc
也可以通过 mapState 映射
获取数据:
$store直接访问
$store.state.user.userInfo.name
mapState辅助函数访问(需要开启命名空间)
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
使用模块中 getters 中的数据:
1)直接通过模块名访问 $store.getters['模块名/xxx ']
2)通过 mapGetters 映射
mapGetters([ 'xxx' ]) mapGetters('模块名', ['xxx']) - 需要开启命名空间获取模块内的mutations方法:
1)直接通过 store 调用 $store.commit('模块名/xxx ', 额外参数)
2)通过 mapMutations 映射
获取模块内的actions方法:
1)直接通过 store 调用 $store.dispatch('模块名/xxx ', 额外参数)
2)通过 mapActions 映射
官网:https://cn.vuejs.org/
setup函数是 Vue 组件中的新选项,它是所有组合式 API 特性的入口点。它的主要目的是替代 Vue 2 中的 data、methods、computed 和 lifecycle hooks 等选项,提供一个更灵活和组织性更强的方式来组织组件逻辑。
特点:
setup 函数在组件创建之前执行,此时组件的 props 已经被解析,并且可以在函数内访问。这使得 setup 成为定义响应式状态和其他响应式逻辑的理想位置。setup 函数接收两个参数:
props:一个包含组件接收的所有 props 的对象。注意,Vue 对这些 props 进行了代理,你应当避免解构它们,以保持响应性。context:一个普通的 JavaScript 对象,包含了 Vue 组件实例的 attrs、slots、emit 等属性。setup 函数的返回值可以是一个对象,该对象的属性将会被暴露给组件的其它部分(如模板或其他选项API),或者返回一个渲染函数。setup 中,你可以使用 ref 和 reactive 来创建响应式状态。ref 用于定义响应式的基本类型值,而 reactive 则用于对象或数组。setup 中使用,但它们的名称有所更改,如 onMounted、onUpdated、onUnmounted 等。示例:
import { ref, onMounted } from 'vue';
export default {
setup(props, { emit }) {
const count = ref(0);
function increment() {
count.value++;
emit('update:count', count.value);
}
onMounted(() => {
console.log('Component is mounted!');
});
return { count, increment };
}
}
Vue 3 中引入了 setup 语法糖 script setup。这是一种新的语法糖,允许在 标签中使用 setup 语法,而无需定义 export default 对象。
script setup 有以下特性:
中定义的所有变量都自动暴露给模板,无需通过 return 语句。 允许更好的类型推断,因为它是基于模块作用域的。setup 函数和 export default,代码更加简洁。 中使用生命周期钩子,如 onMounted。defineProps 和 defineEmits 函数来定义 props 和 emits。示例:
reactive: 接收一个对象类型的数据,返回一个响应式的对象
示例:
import { reactive } from 'vue'
const state = reactive({
count: 100
})
const setCount = () => {
state.count++
}
ref: 接收简单类型 或 复杂类型,返回一个响应式的对象
本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型,再借助 reactive 实现的响应式
注意点:
示例:
import { ref } from 'vue'
const count = ref(0)
const setCount = () => {
count.value++
}
{{ count }}
在 Vue 组件中使用
computed,可以让我们基于现有数据动态计算新的数据值,而且这些值会在依赖的响应式数据发生变化时自动更新。
示例:
原始数据: {{ list }}
计算后的数据: {{ computedList }}
watch用于观察 Vue 实例上的响应式数据的变化。当需要在数据变化时执行一些操作(如数据获取、验证或复杂的逻辑)时,watch是非常有用的。
示例:
{{ count }}
{{ nickname }}
-----------------------
{{ userInfo }}
可选参数:
deep :用于深度监听对象的内部变化immediate :使得侦听器在初次创建时立即触发一次,而不是等待数据变化示例:
{{ count }}
{{ nickname }}
-----------------------
{{ userInfo }}

示例:
父组件通过props向子组件传递数据,子组件通过事件向父组件发送消息。
props接收这些数据。$emit触发事件,父组件通过监听这些事件来响应子组件的行为。父组件:
子组件:
{{ msg }}
模板引用(template refs)允许直接访问DOM元素或组件实例。这在需要直接操作DOM或访问组件的特定方法时非常有用。
用法:
可以使用ref属性在模板中创建一个引用。这个属性的值应该是一个字符串,表示引用的名称。然后,可以在JavaScript部分通过ref API访问这个元素。
注意事项:
onMounted钩子中访问模板引用是安全的。.value访问的DOM元素是实时的,意味着它总是指向当前的DOM元素或组件实例。
provide和inject它们允许跨组件树传递数据,非常适合用于深层嵌套组件或需要共享数据的场景,而不必通过每个组件层手动传递 props。
provide选项允许一个组件向其所有子孙组件提供数据或方法,而无需通过每个单独的组件手动传递。你可以在任何组件中使用provide选项来定义数据或方法,然后在组件的任何后代中使用inject来访问它。
inject选项用于在任何子组件中接收从祖先组件通过provide提供的数据或方法。
父组件:
User: {{ state.user }}
子/孙组件:
User name: {{ userData.user }}
defineOptions是 Vue 3.2 在标签中引入的一个编译时的宏,它允许在单文件组件的块中直接定义组件的选项,如 name, props, emits 等。
示例:
{{ title }}
使用
的组件是默认关闭的——即通过模板引用获取到的组件的公开实例,不会暴露任何在中声明的绑定。可以通过
defineExpose编译器宏来显式指定在组件中要暴露出去的属性
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
当父组件通过模板引用的方式获取到当前组件的实例,获取到的实例会像这样 { a: number, b: number } (ref 会和在普通实例中一样被自动解包)
Vite 是一种现代化的前端构建工具,由原 Vue.js 创建者尤雨溪开发。它使用了原生的 ES 模块(ESM)作为开发时的模块格式,可以实现快速的冷启动和即时模块热更新。Vite 提供了丰富的功能,如 TypeScript 支持、CSS 预处理、代码拆分等,而且通过插件系统可以进一步扩展。
与 Vue CLI 相比,Vite 有几个显著的优点:
使用步骤:
1)安装 Node.js: 确保你的系统已经安装了 Node.js。Vite 要求 Node.js 版本至少为 12.0.0。
2)创建新项目: 使用 Vite 提供的命令行界面快速创建一个新项目。打开你的终端或命令提示符,然后运行以下命令:
npm create vite@latest my-vue-app
这个命令会创建一个名为 my-vue-app 的新目录,里面包含一个基于 Vue 的模板项目。
3)进入项目目录:
cd my-vue-app
4)安装依赖:
npm install
5)启动开发服务器:
npm run dev
Pinia 是 Vue.js 生态系统中的一个状态管理库,通常用于 Vue 3,作为更易用的 Vuex 替代品。Pinia 提供了一种简洁和强大的方式来管理和维护应用的状态。
1)安装
npm install pinia
2)创建一个 pinia 实例 (根 store) 并将其传递给应用:
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')
3)定义Store
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => {
return {
name: "张三",
}
},
actions: {
// 修改state中的数据
changeName(name) {
this.name = name;
}
}
})
4)组件中使用
{{ userStore.name }}
为了从 store 中提取属性时保持其响应性,需要使用
storeToRefs()。它将为每一个响应式属性创建引用。当只使用 store 的状态而不调用任何 action 时,它会非常有用。
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>
在 Pinia 中,state 被定义为一个返回初始状态的函数。
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
// 为了完整类型推理,推荐使用箭头函数
state: () => {
return {
// 所有这些属性都将自动推断出它们的类型
count: 0,
name: 'Eduardo',
isAdmin: true,
items: [],
hasChanged: true,
}
},
})
Getter 完全等同于 store 的 state 的计算值。可以通过
defineStore()中的getters属性来定义它们。推荐使用箭头函数,并且它将接收state作为第一个参数。
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
export const useUserListStore = defineStore('userList', {
getters: {
getUserById: (state) => {
return (userId) => state.users.find((user) => user.id === userId)
},
},
})
Action 相当于组件中的 method。它们可以通过
defineStore()中的actions属性来定义,并且它们也是定义业务逻辑的完美选择。类似 getter,action 也可通过
this访问整个 store 实例,不同的是,action可以是异步的,可以在它们里面await调用任何 API,以及其他 action。
export const useCounterStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
},
},
})
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
// ...
}),
actions: {
async registerUser(login, password) {
try {
this.userData = await api.post({ login, password })
} catch (error) {
return error
}
},
},
})
持久化是指将应用状态保存在用户的浏览器中,即使在浏览器刷新或关闭后,状态也能被保留。
要在 Pinia 中实现状态的持久化,可以使用第三方插件
pinia-plugin-persist。这个插件允许状态自动保存到浏览器的存储系统中,并在应用加载时重新加载这些状态。
使用步骤:
1)安装插件
npm install pinia-plugin-persist
2)创建 Pinia Store
// store.js
import { defineStore } from 'pinia'
export const useMainStore = defineStore('main', {
state: () => ({
counter: 0
}),
actions: {
increment() {
this.counter++;
}
}
});
3)启用持久化
在store 中启用持久化。可以选择哪些状态需要被持久化,以及使用哪种存储方式(例如 localStorage 或 sessionStorage)。
// store.js
import { defineStore } from "pinia";
export const useMainStore = defineStore("main", {
state: () => {
return {
counter: 0,
};
},
actions: {
increment() {
this.counter++;
},
},
persist: {
enabled: true,
strategies: [
{
key: "my-main-store",
storage: localStorage, // 或者 sessionStorage
},
],
},
});
4)在 Vue 应用中使用 Pinia 和持久化插件
在 Vue 应用入口文件中,安装 Pinia 并确保持久化插件被正确加载。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import PiniaPersist from "pinia-plugin-persist";
import './style.css'
import App from './App.vue'
const pinia = createPinia()
pinia.use(PiniaPersist);
createApp(App).use(pinia).mount('#app')