Vue-cli
# vue-cli
vue-cli脚手架 - 可以帮助我们快速搭建出Vue项目.
注意: vue2中,都是使用vue-cli ; vue3中,可以使用vue-cli搭建,但官方更推荐使用vite来搭建,因为它更快更小巧.
# 搭建nodejs环境
Vue-cli依赖一门后端解释性语言nodejs, So, 需要先安装解释器!!
下载nodejs的解释器地址: https://nodejs.org/en/download (LTS长期支持的版本,Current最新版本 - 选LTS)
一路点击下一步,无需额外的操作.
"""
This package has installed:
• Node.js v18.18.0 to /usr/local/bin/node
• npm v9.8.1 to /usr/local/bin/npm
Make sure that /usr/local/bin is in your $PATH.
""" Node相当于python,npm相当于pip!!
dengchuan@MacBook-Air ~ % node -v
v18.18.0
dengchuan@MacBook-Air ~ % node
Welcome to Node.js v18.18.0.
Type ".help" for more information.
> console.log("Hello World!")
Hello World!
undefined
> .exit
dengchuan@MacBook-Air ~ % npm -v
9.8.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
有些时候给npm或node命令升级后可能会导致node和npm版本不对应. 解决办法, 重新搭建node环境!!
该网址可查看nodejs版本相对应的node版本 -- https://nodejs.org/en/download/releases/
若想更新node.js的版本到最新,mac需要这么做:
1.先查看本机node.js版本: node -v
2.清除node.js的cache: sudo npm cache clean -f
3.安装 n 工具,这个工具是专门用来管理node.js版本的, 别怀疑这个工具的名字,是他是他就是他,他的名字就是"n"
sudo npm install -g n
4.安装最新版本的node.js
sudo n stable
5.再次查看本机的node.js版本:
node -v
若想更新npm的版本到最新,mac需要这么做:
1. sudo npm install npm@latest -g
2. 为了提高速度,你可以这样做:
npm config set registry https://registry.npm.taobao.org
npm install -g cnpm --registry=https://registry.npm.taobao.org
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装vue-cli
直接通过
npm install -g @vue/cli
来安装脚手架很慢, 因为要访问国外的资源.
我们可以使用淘宝镜像定制的cnpm来替代npm, 达到加速的效果!!
执行命令:
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
执行完后,在终端上就有两个命令可用于安装第三方模块啦! 1> npm 安装速度慢 2> cnpm 安装速度快,使用它!!
执行命令:
sudo cnpm install -g @vue/cli
执行完后,vue-cli脚手架就安装好啦! 安装完脚手架后,就会有个vue命令!!
Ps:安装指定版本的脚手架 sudo npm install -g @vue/cli@5.0.8
卸载 sudo npm uninstall -g @vue/cli
查看全局安装哪些包 npm list -g
""" 该命令执行成功,则证明vue-cli脚手脚安装成功!
dengchuan@MacBook-Air ~ % vue -V
@vue/cli 5.0.8
"""
注: 若安装cnpm和vue脚手架出错,清除缓存后重新安装!清楚缓存的命令: npm cache clean --force
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建vue项目
后续我们开发项目用vue3!! 示例中是选择vue2作为示范的, 无伤大雅, vue2上所有的写法都能在vue3上完美运行成功.
# 方式一 cmd里
通过vue create命令创建vue项目. 示例中选择的是vue2,当然我们可以选vue3.
# ★ 注意,新建的项目会创建在当前路径下 ; 注意,加上sudo!!
dengchuan@MacBook-Air Desktop % sudo vue create myfirstvue
? Your connection to the default npm registry seems to be slow.
Use https://registry.npmmirror.com for faster installation? Yes
# 键盘上下键移动选第三个,自定义,安装什么自己决定!选中后敲回车.
Vue CLI v5.0.8
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
❯ Manually select features
# 上下键移动,按空格选中与取消选中. 这里,我们选Balel、Router、Vuex这三个第三方组件! 敲击回车到下一步.
# Balel 高版本es语法转化 - 在vue项目中可以写高版本的es语法,它会自动转化成es5的语法,来兼容一些不支持es高版本语法的浏览器!
# Router 路由
# Vuex 状态管理器,简单理解:就是一个存放变量的地方.但浏览器关闭的话,该变量就没啦!
# ★ Router和vuex是写vue项目必用的!!
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
❯◉ Babel
◯ TypeScript
◯ Progressive Web App (PWA) Support
◉ Router
◉ Vuex
◯ CSS Pre-processors
◯ Linter / Formatter
◯ Unit Testing
◯ E2E Testing
# 选择vue的版本,学习为主,此处先选2.x的版本, 3.x与2.x其实差不了多少.
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex
? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
3.x
❯ 2.x
# 包管理文件选择package.json -- 它类比于 Django项目中的reqirement.txt
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Where do you prefer placing config for Babel, ESLint, etc.?
In dedicated config files
❯ In package.json
# 它在问你,这些配置要保存吗?保存后用于下一次创建新项目时使用. 选择No就行
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In package.json
? Save this as a preset for future projects? (y/N) N
# 展示下方的结果,表明vue项目创建成功!
Vue CLI v5.0.8
✨ Creating project in /Users/dengchuan/Desktop/myfirstvue.
🗃 Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...
added 846 packages in 14s
🚀 Invoking generators...
📦 Installing additional dependencies...
added 7 packages in 2s
⚓ Running completion hooks...
📄 Generating README.md...
🎉 Successfully created project myfirstvue.
👉 Get started with the following commands:
$ cd myfirstvue
$ npm run serve
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 方式二 浏览器里
还可以通过 vue ui 命令图形化界面里创建项目. 示例中选择的是vue2,当然我们可以选vue3.
vue ui # -- 图形化界面里创建
- 选择创建项目的路径
- 创建新项目
- 包管理器选择npm (不选也行默认就是npm)
- 选择手动, 手动配置项目
- 选择功能/第三方模块
Babel 它会将项目中ES6,ES7等新语法转成ES5的语法,实现对低版本浏览器语法的兼容
Router 路由
VueX 状态管理器,简单理解:就是一个存放变量的地方.但浏览器关闭的话,该变量就没啦!
- 版本选择2.x
- 保存新预设,随便写个名字,下次创建vue项目时,选它,就有此次创建项目时的这些配置.
2
3
4
5
6
7
8
9
10
11
# 运行vue项目
项目创建好后, 用编译器打开项目!
# 终端运行命令
方式一: 在编译器终端里允许命令,记得加上sudo!!不然权限不够,编译会失败的.
dengchuan@MacBook-Air myfirstvue % sudo npm run serve
> myfirstvue@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 1936ms
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.31.208:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
● 方式二: pycharm里还可以配置此命令,点击个按钮,快速启动.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 绿箭头
方式二: 进行如下配置. 在webstorm中点击绿箭头就能快速上运行项目!!
注意, 图中有npm和node的路径, 应确保正确的.
# Vue项目目录
以后写代码,都在src文件夹下写,其它地方一般不动.
具体文件中每一行代码什么意思, 参考文档: https://www.jianshu.com/p/19a7774248c3
myfirstvue # -- 项目名
├── node_modules # -- 当前vue项目的所有的依赖,小文件很多,可以删掉! -- 类似于py的虚拟环境.
# 它人拿到删除了该文件夹的项目,它人只需要执行 npm install 命令即可再次拥有该文件夹.
# 会将 package.json 文件里的所有依赖都给安装上.
├── public # -- 共用资源
│ ├── favicon.ico # 网址小图标
│ └── index.html # 项目入口页面/vue项目默认首页.
# 单页面开发(整个网站就这一个index,页面的变化都是组件的替换 英文简称spa)
├── src # -- ★ 书写代码的地方
│ ├── assets # -- 网站的静态文件和资源
│ └── logo.png
│ ├── components # -- 一堆小组件(给组件用的组件 非页面组件)
│ └── HelloWorld.vue # 自定义的组件
│ ├── router # -- vue-router相关,安装了该功能自动生成此文件夹
│ └── index.js
│ ├── store # -- vuex相关,安装了该功能自动生成此文件夹
│ └── index.js
│ ├── views # -- 一堆大组件(是页面组件)
│ └── AboutView.vue
│ └── HomeView.vue
│ ├── App.vue # -- !!! 根组件
│ └── main.js # -- ★ 非常重要,是整个项目的入口. 等同于Django的manage.py
├── .gitignore # -- git忽略文件
├── babel.config.js # -- 语法检查. 咋们不用管它.
├── jsconfig.json # -- 无需关注
├── package.json # -- ★ 超级重要,项目配置依赖.不能删!! 等同于Django项目中的reqirement.txt
# 后期node_modules文件夹删除后,该json文件中的依赖可使用npm install重新安装
├── package-lock.json # -- 锁定依赖包.不能删. 意味某个模块会依赖其他模块,它们的版本需要对应.
# 若删了,重新安装该模块时,它依赖的模块会安装最新的.可能会出现问题.
├── README.md # -- 项目介绍
└── vue.config.js # -- vue项目的配置文件,等同于Django项目的settings.py
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
若打开的项目在编译器里只读, 为该vue项目添加权限即可!!
dengchuan@MacBook-Air Desktop % sudo chmod -R 777 myfirstvue
一些补充
简单来说,vue项目创建好后,运行项目,根据vue-cli脚手架自动生成的代码,大抵可知:
App.vue根组件会关联到index.html ;
App.vue根组件通过路由关联AboutView.vue和HomeView.vue这两个页面组件 ;
在HomeView.vue这个页面组件中导入了HelloWorld.vue这个小组件!!
在index.html中有这么两行代码,它的意思是,若浏览器禁用网站的js功能,那么就会显示这段文字.
意味着,vue项目的正常运行的前提是浏览器必须得允许js功能的执行!
<noscript>
<strong>
We're sorry but <%= htmlWebpackPlugin.options.title %>
doesn't work properly without JavaScript enabled. Please enable it to continue.
</strong>
</noscript>
我们说index.html单页面开发,组件的替换其实替换的是这个位置
<div id="app"></div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 如何运作的?
项目是如何运行起来的 / 各个文件是如何协同工作的,逻辑是什么?
# main.js与index.html
尽管对里面的代码不清不楚, 但也无伤大雅.. main.js文件一般不会动它!! 我们也不用深究里面的代码!!
main.js是项目入口文件, 经实验,创建的vue实例挂载的是index.html里id为app的div. 是不是感觉很amazing?
当初我看到时也百思不得其解, 查阅资料, 发现跟webpack有关..
参考的文档: https://blog.csdn.net/qq_36145914/article/details/86497123
(了解即可)
另外, render: h => h(App)
又是什么? 箭头函数, 此处的h指代的是createElement函数, 跟啥虚拟dom有关..
另外, .$mount('#app')
相当于 el: '#app',
// 分别导入: Vue库、App组件、路由配置、状态管理器
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 关闭生产模式下的错误提示信息
Vue.config.productionTip = false
/*
new Vue({...})创建一个vue实例
将路由配置、状态管理器以及App组件注入/渲染到vue实例中.
.$mount('#app') 将Vue实例挂载到id为"app"的元素上.
*/
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 组件的三部分
我们重新写App.vue和HelloWorld.vue文件,便于我们理解执行逻辑!!
(因为默认里面写了路由这些相关的代码.我们暂且不需要掌握)
1> <template>
标签里是以前我们在反引号里写的html代码,同样的,特别强调,组件必须在一个标签里.eg:div标签.
2> <script>
标签里写js、导入以及export default
export default {} 该对象里写之前学的data、methods、watch、computed、生命周期函数等!
3> <style>
标签里写样式.
注意: <style scoped>
表明, 写的样式只在当前组件有效!!
也就是说, 这样写, 父组件里用了子组件, 子组件是不会应用父组件里写的样式的!!
另外,注意: 父组件中导入子组件export default的对象接着对子组件进行注册
只不过, 该对象里不用写template:反引号
,会自动关联子组件<template>
标签里的东西.
特别注意!! 示例代码截图中,helloWorld_obj是一个对象; export default导出的也是一个对象!!
Ps: test.html单独运行,或者 运行 当前的vue项目!! 运行结果都如上图截图所示!!
why? 你可以这样对比理解..
main.js里有vue实例,main.js与index.html相关联. -- 相当于test.html里写了个vue实例 (test.html对标index.html)
main.js里的vue实例挂载id为app的div -- 相当于test.html中的vue实例挂载index.html中挂载id为app的div
main.js里的vue实例中加载了根组件App.vue -- 相当于test.html中的vue实例里面写了一个名为App的局部组件
项目运行后,根组件App.vue会自动渲染到挂载点 -- 相当于test.html中在挂载点写子组件标签
根组件App.vue里导入子组件HelloWorld.vue -- 相当于名为App的局部组件里编写了一个名为HelloWorld的子组件
2
3
4
5
6
# vue项目中组件通信
自定义属性实现父传子 ; 自定义事件实现子传父.
# 示例代码
APP.vue
<template>
<div id="father">
{{ fullname }}
<button @click="handleClick">点我名字变化!</button>
<br>
子传父: x: {{ x }}
<hr>
<HelloWorld :fullname="fullname" @myevent="handleReceive"></HelloWorld>
</div>
</template>
<style>
#father {
width: 300px;
margin: auto;
padding: 10px;
border: 1px solid bisque;
}
</style>
<script>
import HelloWorld from "@/components/HelloWorld"
export default {
name: 'App',
data() {
return {
isActive: true,
fullname: "lqz",
x: "",
}
},
methods: {
handleClick() {
this.isActive = !this.isActive
this.fullname = this.isActive ? 'lqz' : '彭于晏'
},
handleReceive(x) {
this.x = x
}
},
components: { // 注册组件,即在父组件中使用子组件!
// 'HelloWorld': HelloWorld // ★ 简写-可以简单的只写import导入时给小组件起的名字 HelloWorld
HelloWorld
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
HelloWorld.vue
<template>
<div>
父传子: {{ fullname }} <br>
<input type="text" v-model="x">
x: {{ x }} ; y: {{ y }}
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: ["fullname"], // 父传子的变量fullname无需在data里申明,写在props中后直接用就行
data() {
return {x: 10, y: 20,}
},
methods: {
handleSend() {
this.$emit('myevent', this.x)
}
},
watch: {
x(val) {
this.handleSend()
}
},
created() {
this.handleSend()
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 代码逻辑
# 执行结果
有两个组件,APP.Vue和HelloWorld.vue 并且根组件APP里注册了HelloWorld组件
1> 父传子, 点击按钮, 显示的名字同步改变!!
2> 子传父, 先是在生命周期的created函数中就传了一次;
后因为双向绑定+监听,当数据改变时,会重新传递!!
2
3
4
有个小细节: 根组件的 <template>
里的代码覆盖了index.html中 <div id="app"></div>
这里的代码!!
# props配置项
三种使用方式
特别注意!! 父传子,经过实验. (示例代码中只是props的基本使用!!)
<helloWorld fullname="true"></helloWorld>
传过去的fullname的值是true, 该true是String类型的数据!!
<helloWorld :fullname="true"></helloWorld>
传过去的fullname的值是true, 该true是Boolean类型的数据!!
★★★ props的三种使用方式,任选其一即可! 注意哈,String,S是大写的!!
1- 基本使用
props: ["fullname"]
2- 进行属性认证
props: {
fullname: String, // 意味着接受父组件传过来的fullname,必须是string类型的数据!!
}
3- 限定类型、限定必传、限定默认值
props: {
fullname: {
type: String,
// false表明没有限定必传(即子组件标签上没有绑定名为fullname的属性)
required: false,
// 若没有传的话,其默认值为‘啦啦啦’
default: "啦啦啦",
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# es6导入导出
注意: 在vue项目中, 导入时, @符号表示src的路径! 导入时,文件的.vue后缀、.js后缀都可以省略!
下方的示例中使用的是默认导出, 还有命名导出等方式.. 具体的参考文档: https://segmentfault.com/a/1190000039957496
暂且记住一点, 命名导出的话, 导入时 import {导出时的命名,导出时的命名,..} from 路径
需要加大括号!!
示例的目录结构如下:
my
├── other
│ └── index.js
├── one.js
├── two.js
└── test.html
2
3
4
5
6
代码逻辑
注意代码截图中用 ★ 标注的注释!!
运行结果
# mixin混入
需求: 父组件App.vue里使用子组件HelloWorld.vue, 这两个组件里都有同一个点击事件, 点击事件关联的函数体代码都是一样的!!
点击弹出一个框, 框中显示的内容是各自组件里的数据..
mixin混入: 可以把多个组件共用的配置提取成一个混入对象!!
# 最初的代码
浅红色标柱的代码是公共的/一样的, 可以提取出来!!
# 使用混入
第一步: 提取公共的代码, 定义混入.. 此处, 我们在src目录下新建mixin文件夹, 在mixin文件夹下创建index.js文件.
第二步: 注册混入, 有两种方式, 选择其中一种方式即可.
1> 全局注册 - 在main.js文件中注册, 注册后所有组件都可以使用混入的内容.
2> 局部注册 - 在组件中注册后,该组件才可以使用混入的内容.
# 全局注册
下方截图主要观察 index.js 以及 main.js中 框起来的代码.
PS: 若混入的index.js中有多个命名导出.. 那么全局注册这样处理. 举个例子:
import {hunhe,hunhe2} from '@/mixin'
Vue.mixin(hunhe)
Vue.mixin(hunhe2)
2
3
4
# 局部注册
以子组件HelloWorld.vue为例
关键代码就两行: import {myMixin} from "@/mixin";
mixins: [myMixin]
<template>
<div>
<button @click="handleShowName">点击弹窗</button>
</div>
</template>
<script>
import {myMixin} from "@/mixin";
export default {
name: 'HelloWorld',
data() {
return {
name: "child_路飞"
}
},
methods: {},
mixins: [myMixin]
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 插槽的使用
默认插槽、具名插槽 (其实在前面已经讲解过了)
<template v-slot:插槽名字>
还可以简写 <template #插槽名字>
页面展示效果如下:
# 存储数据
sessionStorage - 临时存储, 浏览器关闭或关闭标签页 就没啦!
localStorage - 永久存储, 除非手动清理/浏览器存储空间满了!
cookie - 有个过期时间, 过期时间一到就没啦! + 发送请求时会自动携带它.
前端存数据的三个地方 - cookie、sessionStorage、localStorage.
在cookie中存储需要借助第三方插件vue-cookies 暂且略过.
★ 借助这三个东西, 也可以实现组件间的通信!!
sessionStorage.setItem('name', 'lqz') // 设置值
sessionStorage.getItem('name') // 取值
sessionStorage.removeItem('name') // 删除值
sessionStorage.clear() // 清空sessionStorage中所有数据
localStorage.setItem('name', 'lqz')
localStorage.getItem('name')
localStorage.removeItem('name')
localStorage.clear('name') // 清空localStorage中所有数据
2
3
4
5
6
7
8
9
应用场景:
无需登陆就可以将商品加入购物车,关闭浏览器后,重新打开浏览器,发现刚加入购物车里的商品还在!
实现原理 - 前端将商品信息加到了localStorage中!!
App.vue
<template>
<div id="father">
<p>
用户名: {{ username ? username : "还未获取" }}
</p>
<button @click="handleSave">点击</button>
<p style="color: rgb(128,128,128)">
1> 起初 - 用户名处显示 "还未获取" <br>
2> 点击按钮 向sessionStorage中放数据 - 用户名处显示存入的数据 "lqz" <br>
3> 5s后 缓存的数据消失 - 用户名处显示 "缓存数据消失" <br>
</p>
</div>
</template>
<style scoped>
#father {
width: 550px;
margin: auto;
padding: 10px;
border: 1px solid bisque;
}
h3 {
background-color: bisque;
}
</style>
<script>
export default {
name: 'App',
data() {
return {
username: ''
}
},
methods: {
handleSave() {
sessionStorage.setItem('name', 'lqz')
this.username = sessionStorage.getItem('name')
/* 注意点:
setTimeout是异步的,它不会阻塞在这,时间到了会执行里面的回调函数
这里用了箭头函数,确保该处的this指向是vue实例,而不是window对象.
*/
setTimeout(() => {
sessionStorage.removeItem('name')
this.username = "缓存数据丢失."
}, 5000)
}
},
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# vue3的变化
前面的讲解都是基于vue2实现的, 我们后续开发项目用vue3, vue3是兼容vue2的!!
vue3变化参考文档: https://www.cnblogs.com/liuqingzheng/articles/16840372.html
★ 学的vue2的所有东西都可以直接写在vue3上, 完全支持!!
# 创建vue3的项目
# webstorm里
它会自动选择vue3创建!! 创建时是默认的配置, 是没有 Router和 Vuex的.. 不碍事,后面可以手动加入.
另外, 通过这种方式创建的项目, 快速启动的绿色按钮也不需要自己配置啦!!
但在我的mac上实践了下,会报错, 在项目根目录下运行这两行命令完美解决 rm -rf node_modules
; npm install
# 使用vite
创建vue3的项目:
- 使用vue-cli创建,跟vue-cli创建vue2项目基本一致
- 使用vite创建
step1: 创建工程 “利用vite新创建的工程是没有node_modules文件夹的”
npm init vite-app vue3_1
step2: 进入项目工程 cd vue3_1
step3: 安装依赖 npm install “项目根目录下就会多出node_modules文件夹”
step4: 运行,注意命令 ★ npm run dev “会发现,运行的特别快!!之前用vue-cli创建的运行起来还需编译,现在编译都不需要”
2
3
4
5
6
7
8
可以浅看下代码, 利用vite创建好项目后, 最开始就默认有的代码是如何实现这个页面的..
可以发现里面使用的vue2的语法, 都是学过的, so easy. 有效的证明了“vue3兼容vue2嘛!!”
细心点, 可以发现, <template>
标签里的html代码无需特地放在 一个div标签里啦!!
# 组合式API
vue2使用的是配置项API , vue3中推荐使用组合式API!!
以后vue3不建议组件中使用data、methods.. 这种配置项API; 建议使用setup这种组合式API!!
<template>
{{ name }}:{{ age }}:{{ nums }} <br>
<button @click="age++">点击年龄加一</button>
<button @click="handlerNumAdd">点击数字加一</button>
<br>
身高:{{ person.height }} 体重:{{ person.weight }}
<button @click="handlerHeightAdd">点击身高加1cm</button>
<br>
出生地:{{ BirthPlace }}
<button @click="handlerChangeCity">点击修改城市</button>
<br>
监听它:{{ temp }}
<button @click="temp++">点击监听的变量加一</button>
</template>
<script>
import {ref, reactive, computed, watch} from 'vue'
export default {
name: 'App',
setup() {
/* 定义变量
* 相当于在vue2的配置项API data(){return {name:'lqz',age:18}}
* */
// 若不加ref,那么点击按钮,age变量的值会加1,但是页面上{{age}}不会变/不会响应式的改变.
// 若不加reactive,那么点击按钮,person对象的height的值是会改变的,会加1,但是页面上{{person.height}}不会响应式的改变.
const name = ref('lqz')
const age = ref(18)
const nums = ref(0)
const person = reactive({
height: 172,
weight: 110,
})
/* 定义函数方法
* 相当于在vue2的配置项API methods:{handlerNumAdd() {}},
* */
function handlerNumAdd() {
// 因为使用了ref,所以nums变量变成了ref对象!
// 注意,若未使用ref const name = 'lqz' , name变量是常量是不能改变的!
// (内存地址不能变,若是复杂数据类型,比如对象,对象内存地址不变,但里面的属性是可以变的)
// ★★★《基本数据类型》用ref包裹一下,使之变成响应式. 在模版中直接使用;在setup(){}中需要nums.value获取真正的值.
// ★★★《数组、对象类型》用reactive包裹一下,使之变成响应式. 在模版中和setup(){}中都直接使用;
console.log(nums, typeof nums)
nums.value += 1
}
function handlerHeightAdd() {
person.height += 1
}
// ★★★ 可以写多个计算,也可以写多个监听
/* 定义计算属性
* 相当于在vue2的配置项API computed: {}
* */
const student = reactive({
nation: "中国",
city: "成都"
})
let BirthPlace = computed(() => {
return student.nation + student.city
})
// function handlerChangeCity(){}
let handlerChangeCity = () => {
student.city = "北京"
}
/* 定义监听属性
* 相当于在vue2的配置项API watch: {}
* */
const temp = ref(1)
watch(temp, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
// ★★★ setup中可以写变量,写函数等, 但只有return了,在模版中才可以使用!
// 这使得不会像vue2里面一样全部动态渲染,vue3需要啥渲染啥.
return {
name,
age,
nums,
handlerNumAdd,
person,
handlerHeightAdd,
BirthPlace,
handlerChangeCity,
temp,
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 生命周期
"[生命周期]"
- 在vue3里,若用vue2的配置项写法,生命周期的8个函数,有两个需要改一下名字
beforeDestroy 改名为 beforeUnmount
destroyed 改名为 unmounted
- 在vue3里,若使用vue3的组合式API写法 对应关系如下
“但要注意,setup()一执行,就认为beforeCreate和created就执行完了.”
“比如,在setup中写 import {onMounted} from 'vue'; onMounted(() => {})”
beforeCreate ===> setup()
created ===> setup()
beforeMount ===> onBeforeMount
mounted ===> onMounted
beforeUpdate ===> onBeforeUpdate
updated ===> onUpdated
beforeUnmount ===> onBeforeUnmount
unmounted ===> onUnmounted
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# toRefs
对象解压, 就不必在模版中 对象.xx 取值啦!
<template>
身高:{{ person.height }} 体重:{{ person.weight }} <br>
姓名:{{ name }} 年龄:{{ age }}
</template>
<script>
import {reactive, toRefs} from 'vue'
export default {
name: 'App',
setup() {
const person = reactive({
height: 172,
weight: 110,
})
const fullName = reactive({
name: "dc",
age: 19,
})
// es6语法中的对象解压
/* 下面的代码等同于
return {
person,
name:fullName.name,
age:fullName.age,
}
* */
return {
person,
...toRefs(fullName),
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37