【vue3】创建vue3项目的两种方式 setup函数 ref和reactive 计算和监听属性 生命周期 hooks toRefs script setup的作用和lang=ts 后台管理模板
昨日回顾
# 1 props
-不需要在data中定义了,他就在当前组件对象身上了 this
-props:[]
-props:{name:String}
-props:{name:{require:,default:...}}
# 2 组件间通信
-1 父子:父传子 ,自定义属性
-2 子传父,自定义事件
-3 ref属性
-4 localStorage,sessionStorage,cookies
-5 vuex
# 3 插件 --> 使用第三方插件(vue-router,vuex,elementui)
-导入
-Vue.use(elementui)----> install(){}
-自定义插件:
-xx.js 中 export default{
install(vue){
1 自定义指令
2 往vue中放全局 Vue.prototype.$axios=axios
3 执行minxin
4 全局组件
}
}
# vuex:状态管理器,vue存数据的地方,跨组件间通信
-vue2使用版本是vuex3
-vue3使用版本是vuex4
-npm install vuex@3
-三个状态:
state:真正存数据的
mutations:修改state的地址 state.变量名,修改即可
actions:判断,跟后端交互,调用mutations的地方 context.commit
-在组件中使用
-模板中: {{$store.state.变量名}}
-js中:
-直接用:this.$store.state.变量名
-调用mutations:this.$store.commit('mutations')
-正常套路:触发actions,this.$store.dispatch()
# vue-router
-vue-router:3版本对应vue2,4版本对应vue3
-单页面应用:index.html,以后都是页面组件间的切换,借助于vue-router
-使用步骤:
-1 基本使用,router/index.js---->routes,加对象 {},加入路径后,访问这个路径就显示指定的组件
-2 跳转到不同的页面
-js控制:this.$router.push('路径') ,可以写个对象
-标签控制:<router-link to属性=路径>,也可以写个对象
-3 跳转到别的页面传参数
-?name=lqz&age=19 取:this.$route.query.name
-/books/1/ index.js 中配置路由,取:this.$route.params.id
-路由嵌套:routes内部对象中写: children ---》/goods/list
-路由跳转:
-html中跳转:router-link to属性 可以之间写字符串路径,数据绑定对象{}
-js跳转:this.$router.push('goods')
-跳转携带数据:
-get地址中参数:this.$route.query.参数名
-路由中分割出来的参数:this.$route.params.【router/index.js的routes使用:绑定的】
-路由守卫:
-进入该路径之前,进行一些逻辑判断,允许进还是不允许
-权限的控制
-router.beforeEach()
-router.afterEach()
-全局路由守卫
-前置守卫
-后置守卫
-前置守卫
router.beforeEach((to, from, next) => {
// 1 取出cookie中token
// 2 判断如果不是login页面,from对象,就是路由对象,判断一下,如果是,next()
// 3 如果不是,判断token的值是否为空,如果为空,弹窗,跳转到login
// router.push({name: 'login', params: {id: 99}})
// router.push('/login/88')
next({name:'login',params:{id:33}})
})
- localStorage,sessionStorage,cookie
-cookie:借助于第三方 vue-cookies
今日内容
1 vue3介绍
# 1 vue项目的版本,新项目使用vue3,有部分老项目使用vue2
# vue3 的变化
1.性能的提升
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
2.源码的升级
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现和Tree-Shaking
- Tree-Shaking:摇晃树 --> 掉树叶
意思就是将代码中不用的部分给删掉了
3.拥抱TypeScript
Vue3可以更好的支持TypeScript
4.新的特性
Composition API(组合API) 最新的特性
setup配置
ref与reactive
watch与watchEffect
provide与inject
新的内置组件
Fragment
Teleport
Suspense
其他改变
新的生命周期钩子 换了名字
data 选项应始终被声明为一个函数
移除keyCode支持作为 v-on 的修饰符
5 组合式API和配置项API
vue2 :配置项API
new Vue({
el:'#app',
data:{}
})
vue3: 组合式API
setup(){
let name='lqz'
let add=()=>{
}
return {name, add}
}
组合式api:
2 创建vue3项目的两种方式
# vue-cli:创建vue2和vue3
-跟之前一样
# vite:创建vue3,创建最新
npm init vue@latest
# Pinai
# vite创建另一种方式:创建vue3.0.4版本
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
# 启动的两种方式
# 以后再页面中的this,已经不是vue2中的vc对象了,是一个代理对象
vue-cli创建Vue3项目
# 创建跟之前vue2 一样,只是选择vue版本的时候,选择vue3
# 创建完成,使用pycharm打开,并运行
# eslint是什么?
类似python的PEP8编码规范。而且不符合规范时,项目无法编译。
# history模式
补充说明,history模式:
history风格的router在这里:
npm run serve
本质执行的是package.json
中的如下:
可以改名字:
main.js
create(app)创建一个Vue对象。
Vue3建议不使用配置项api,推荐使用组合式api。
Vite创建Vue3项目
# 新建的前端构建工具,最大的优势就是速度快
https://cn.vuejs.org/guide/scaling-up/tooling.html#project-scaffolding
# 使用步骤:
- 安装 :npm init vue@latest
- 按需选择,vueRouter
- cd到项目中执行cnpm install 把依赖装好
- 运行:npm run dev
- vueRouter:跟之前一样
- Pinia:用来替换Vuex的,新一代的状态管理器
- 链式调用
# 在Vite创建的项目里使用Vuex:
1.在Vite项目新建目录和文件 store/index.js
2.将Vue3项目中的 store/index.js文件的代码复制到Vite创建的store/index.js中。
3.在Vite项目的main.js注册插件
import vuex from './stores/index'
const app = createApp(App)
app.use(vuex)
-index.js:
import { createStore } from 'vuex'
export default createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
# 为什么这么快
-创建项目快----》不安装第三方依赖
-执行项目,热更新----》按需编译
Vite的优点:特点速度快
创建项目:
添加vue rounter:
使用pinia(vuex5)做状态管理:
继续按照图片配置:
不懂的就选择NO。
Vue3目录结构
main.js:
Vite项目没有下第三方依赖:还需要下依赖
项目运行命令也发送了变化:
npm run dev
Vite的优点
访问哪个页面,就编译哪个页面,也就是只有用的时候才会进行编译。而不是每次都编译整个项目的所有页面。
3 setup函数
# vue 新增的setup配置项函数,
-在里面可以定义变量
-定义函数
-必须return 变量和函数,在模板中才能使用
Vue3创建实例和Vue2的区别
# vue2的创建vue实例和vue3创建vue实例的区别
-new Vew()---->是Vue的实例,里面有$store,$refs...
-createApp(App)--->是个对象,对象里有东西,没有$store,$refs...,以后有用,都是导入使用
# 以后vue3 的<template>,里面不需要写一个div标签了
# 以后都写在setup函数中,定义变量,定义函数,一定要return,在template中才能使用
# 失去了响应式
Vue3:
Vue2:
查看Vue3 app对象:
查看Vue2 Vue实例:
总结:Vue2会创建Vue的实例,里面有$store...Vue3创建的就是一个对象,不再是Vue的实例了。总的来说,Vue3就是为了不使用this。以后使用都是导入使用。
还有区别,Vue3的template不需要只写在一个div里面了。
使用组合式api,核心就是setup函数。以后都在setup函数中写组合式api。
示例:
在setup申明变量:
需要return返回出去一个对象:
点击按钮年龄加一:
怎么使用setup中的数据,直接用即可,无需使用this。修改setup中定义的数据,页面并不会变化,因为没有做数据和页面的双向绑定,失去了响应式。
<template>
<h2>{{ name }}</h2>
<h3>{{ age }}</h3>
<button @click="handleClick">点我看美女</button>
<br>
<button @click="handleAdd">点我,age+1</button>
</template>
<script>
export default {
name: 'App',
setup() { // setup中没有this了
// 以后所有的变量定义函数编写,都写在这个函数中
// 定义变量 如果这么写,变量渲染没问题,但是没有响应式,页面变了,变量不会变
let age = 19
let name = 'lqz'
// 定义函数
function handleClick() {
alert('美女~~~')
}
let handleAdd = () => {
console.log('我要开始加了')
age=age+1
console.log(age)
}
// 函数必须有返回值
return {
age, name, handleClick, handleAdd
}
}
}
</script>
4 ref和reactive
# 导入使用:import {ref, reactive} from 'vue'
# 有响应式
-以后定义变量,如果想有响应式就用 ref 包裹起来,再修改变量,需要用 变量名.value 修改
# 配置项api和组合式api可以混写,不建议
-在前在data中定义的变量
-在setup中定义的变量
-总结:
在setup中定义的变量和函数,在之前配置项api中可以直接使用this.变量,函数调用即可
但是在原来配置项中定义的变量,函数,在setup中无法使用
# 不同类型做响应式
ref通常用来包裹,数字,字符串类型,以后使用 xx.value
reactive用来包裹数组和对象类型 以后使用 直接用即可
# 总结
ref定义的数据:
操作数据需要.value,读取数据时模板中直接读取不需要.value。
reactive定义的数据:
操作数据与读取数据:均不需要.value
# Vue2和Vue3的响应式区别
响应式会降低速度,直接渲染较快。通过ref来自定义哪些变量需要响应式,哪些变量无响应式。而Vue2是监听所有变量,比较消耗资源。
ref
想要实现数据和页面的双向绑定,需要使用ref.
先导入ref:
这里age变成了ref对象:

真正的值在value中。
如何实现响应式:
实现名字后面加?:
配置项api和组合式api可以一起写,但是不建议:
在setup中定义的变量和函数,在之前配置项api可以直接使用this获取这些变量和函数。但是这个this不是原来的this了 。
reactive
申明对象时:
使用ref包一下。
需要使用value来修改值:
ref对象通过点value可以获取到proxy代理对象。
使用reactive:
可以直接修改:
如果使用插值语法渲染,直接将变量名放在template就行了。
<template>
<h2>{{ name }}</h2>
<h3>{{ age }}</h3>
<br>
<button @click="handleAdd">点我,age+1</button>
<br>
<button @click="handleChangeName">点我name变化</button>
</template>
<script>
import {ref, reactive} from 'vue'
export default {
name: 'App',
setup() {
let age = ref(19) // age 已经不是数字了,是RefImpl的对象
let name = ref('lqz')
let handleAdd = () => {
console.log('我要开始加了,age是', age)
age.value = age.value + 1
console.log('我要开始加了,age是', age.value)
}
function handleChangeName(){
name.value=name.value+'?'
console.log(name)
}
return {
age, name, handleClick, handleAdd,handleChangeName
}
}
}
</script>
5 计算和监听属性
5.1 计算属性
# computed 的配置项中的写法,不建议用了
computed:{
fullName(){
return this.firstName+this.lastName
}
},
# vue3 新写法
let person = reactive({
firstName: '',
lastName: '',
})
let fullName = computed(() => {
return person.firstName + person.lastName
})
# 计算属性取值和修改值
let fullName = computed({
get() {
return person.firstName + person.lastName
},
set(value) {
person.firstName = value.slice(0, 1)
person.lastName = value.slice(1)
},
})
准备:
使用计算属性:
之前的写法:(不建议使用,还是可以用)
现在的写法:
需要导入computed函数。
换一种写法:
计算属性反向改值
修改计算属性的值,反向修改变量。
获取属性触发get,修改属性触发set。
修改计算属性时,反向修改变量:
value是计算属性经过修改之后的值。
export default {
name: 'App',
// computed:{
// fullName:function (){}
// },
setup() {
// 1 计算属性案例1
// let firstName = ref('刘')
// let lastName = ref('清政')
// // 定义计算属性
// let fullName = computed(() => {
// return firstName.value + lastName.value
// })
// 2 计算属性案例2
let person = reactive({
firstName: '刘',
lastName: '清政',
})
// 定义计算属性
person.fullName = computed({
get() {
return person.firstName + '-' + person.lastName
},
set(value) {
console.log(value)
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return {
person
}
}
}
5.2 监听属性
# 组合式api写法,只要name发生变化,就会触发匿名函数执行
let name = ref('lqz')
watch(name, (newName, oldName) => {
console.log('name变了')
console.log('老的', oldName)
console.log('新的', newName)
})
# watchEffect 用法,只要age变化,就会执行,age不变化,就不会执行
watchEffect(() => {
console.log(age.value)
})
watch也需要导入。
只要变量变化,触发匿名函数执行:
查看前端:
watchEffect
只要里面使用到的变量发送了变化,这个匿名函数就会执行。
代码:
import {computed, watch, ref, reactive, watchEffect} from 'vue'
export default {
name: 'App',
setup() {
// 1 计算属性案例1
let name = ref('lqz')
// 定义监听属性
watch(name, (newValue, old) => {
console.log('name变了')
// console.log(old)
// console.log(newValue)
})
// vue3 多的watchEffect,只要函数中使用的变量发生变化,它就会触发
watchEffect(() => {
// 只要该函数中使用的变量发生变化,它就会触发
// let a = name.value + '?'
console.log('watchEffect配置的回调执行了')
})
return {
name
}
}
}
6 生命周期
# Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
- vue2 vue3
beforeCreate ===> beforeCreate
created ===> created
beforeMount ===> beforeMount
mounted ===> mounted
beforeUpdate ===> beforeUpdate
updated ===> updated
beforeDestroy ===> beforeUnmount
destroyed ===> unmounted
beforeDestroy ===改名为===> beforeUnmount
destroyed ===改名为===> unmounted
# Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
beforeCreate ===> setup()
created ===> setup()
beforeMount ===> onBeforeMount
mounted ===> onMounted
beforeUpdate ===> onBeforeUpdate
updated ===> onUpdated
beforeUnmount ===> onBeforeUnmount
unmounted ===> onUnmounted
# 以前写在created中的代码,现在直接写在setup开始即可
let show = ref(false)
axios.get().then(res=>{
show.value=res.data.show
})
setup在beforeCreate之前执行。
准备:在组件中写生命周期钩子函数
导入:
查看:
不推荐配置项写法,将生命周期函数统统写在setup中:
页面一加载,向后端发送请求:
直接在setup中间写。
7 hooks
# 什么是hook?——
本质是一个函数,把setup函数中使用的Composition API进行了封装。
类似于vue2.x中的mixin。
自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂
7.1 hook/usePoint.js
import {onMounted, onUnmounted, reactive} from "vue";
export default function () {
let p = reactive({
x: 0,
y: 0
})
function getPoint(event) {
console.log(event)
p.x = event.pageX
p.y = event.pageY
}
// 声明周期钩子的onMounted,当页面挂载就会执行
onMounted(() => {
// 给数鼠标点击增加监听,当点击鼠标,就会执行这个函数
window.addEventListener('click', getPoint)
})
// 组件被销毁时,把功能去掉
onUnmounted(() => {
window.removeEventListener('click', getPoint)
})
return p
}
7.2 在想使用的组件中引入使用即可
<template>
<h2>x坐标是:{{ p.x }},y坐标是:{{ p.y }}</h2>
</template>
<script>
import {reactive, onMounted, onUnmounted} from 'vue'
import usePoint from '../hook/uesPoint.js'
export default {
name: "Point",
setup() {
let p = usePoint()
return {p}
}
}
</script>
<style scoped>
</style>
8 toRefs
# 以后setup的返回值可以直接使用
setup() {
let data = reactive({
name: 'lqz',
age: 19,
gender: '男'
})
return {...toRefs(data)}
}
# 以后在模板中直接用 {{name}}
export default {
name: 'App',
setup() {
let data = reactive({
name: 'lqz',
age: 19,
isShow: true
})
function handleShow() {
console.log('ssdaf')
data.isShow = !data.isShow
data.age++
}
return {
...toRefs(data),
handleShow
// data
}
}
}
使用torefs:
在前端无需使用data.name,这种方式使用插值:
...toRefs(data)
解构赋值,相当于;
只使用...
:
9 script setup的作用和lang=ts
<script setup>
import {ref} from 'vue'
let name = ref('lqz')
let handleClick = () => {
alert('美女')
}
</script>
# 以后 这个script中的代码直接放到 setup函数中,不用return了
#lang=ts
里面代码使用ts写,而ts完全兼容js,继续写js代码没问题
Vue3高版本,可以在script标签中直接定义变量,会自动放入setup函数中:
导入组件后无需注册直接使用:
以后都不需要导入导出组件了。
支持ts代码;
查看elementui写的Vue3:
父传子需要使用defineProps接受:
10 后台管理模板
# vue-admin-template-master
-跑起来
-package.json 第7行加入
"dev": "set NODE_OPTIONS=--openssl-legacy-provider & vue-cli-service serve",
-网址:github.com/PanJiaChen/Vue-admin-template
# java版的若依
带权限控制的后台管理模块 ---前端---> vue-element-admin
# python :
django-vue-admin ---前端---> D2Admin
# python flask-vue-admin
# go:gin-vue-admin
# element前端 + Vue rbac后台管理
https://gitee.com/liuqingzheng/vue_admin
https://gitee.com/liuqingzheng/rbac_manager
练习
# 创建vue3项目,在setup中写看美女案例
# 练习监听属性和计算顺序
# 从后端接口拿数据展示在页面上
-------------------------------------
# app
随机图片
<template>
<h1 class="text-center">随机美女图片</h1>
<div class="text-center">
<img @click="" :src="default_img" alt="" style="width: 300px">
</div>
<br>
<div class="text-center">
<button @click="startFunc" class="btn btn-success ">点我开始随机</button> <!-- 当没有给函数传参时,会把点击事件传进来 -->
<button @click="stopFunc" class="btn btn-success ">点我停止随机</button>
</div>
</template>
<script setup>
import {ref, reactive} from 'vue'
let imgList = reactive(['https://img2.woyaogexing.com/2022/10/23/af963193e9fb67ee!400x400.jpg',
'https://img2.woyaogexing.com/2022/10/22/95afdd5cd39d556d!400x400.jpg',
'https://img2.woyaogexing.com/2022/10/21/f06c65142fe50c19!400x400.jpg',
'https://img2.woyaogexing.com/2022/10/20/c0135f7e74050a74!400x400.jpg',])
let default_img = ref('https://img2.woyaogexing.com/2022/10/20/c0135f7e74050a74!400x400.jpg')
let timeTool = null
function stopFunc() {
clearInterval(timeTool)
timeTool = null
}
function startFunc() {
if (timeTool === null) { // 第二次点击的时候timeTool不为null,而是存放一个定时器。
timeTool = setInterval(() => {
let i = Math.floor(Math.random() * imgList.length)
default_img.value = imgList[i]
}, 20)
}
}
</script>
<style scoped>
</style>
监听属性和计算属性
<template>
<input type="text" v-model="userInput">
<input type="text" v-model="cuteName">
</template>
<script setup>
import {watch, ref, computed} from "vue";
let userInput = ref('')
let cuteName = computed({
get() { // 调用计算属性时会触发
if (userInput.value.length === 0) {
return ''
} else {
return '= = cute--->' + userInput.value
}
}, // 修改、设置计算属性时会触发,value是修改之后的值
set(value) {
userInput.value = ''
},
})
watch(userInput, (newName, oldName) => { // 每次修改userInput都会触发该函数
if (newName.length >= 8) {
alert('= = 你输入的名字好长')
}
}
)
</script>
<style scoped>
</style>
与后端交互
<template>
<h2>serverView</h2>
<h2>{{ show }}</h2>
</template>
<script setup>
import axios from 'axios'
import {ref} from "vue";
let show = ref('')
axios.get('http://127.0.0.1:8000/api/v1/movies/').then(res => {
show.value = res.data
})
</script>
<style scoped>
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY