vue + echarts 快速入门
vue + echarts 快速入门
本案例即有nodejs和vue的基础,又在vue的基础上整合了echarts
Nodejs基础
1、Node简介
1.1、为什么学习Nodejs(了解)
- 轻量级、高性能、可伸缩web服务器
- 前后端JavaScript同构开发
- 简洁高效的前端工程化
1.2、Nodejs能做什么(了解)
Node 打破了过去 JavaScript 只能在浏览器中运行的局面。前后端编程环境统一,大大降低了前后端语言切换的代价。以下是Node可以实现的工作:(仅作了解)
- Web 服务器
- 命令行工具
- 网络爬虫
- 桌面应用程序开发
- app
- 嵌入式
- 游戏
- …
1.3、Node是什么
Node.js®是基于 Chrome的V8 JavaScript 引擎构建的JavaScript运行环境。
Node.js不是新语言,也不是一个框架或者一个库,而是一个软件。
Node.js是一个 JavaScript 运行环境 ,说白了,就是用来运行js的。
官网:https://nodejs.org/en/
中文官网:https://nodejs.org/zh-cn/
1.4、Nodejs架构和运行过程
1.4.1、Natives modules
- 当前内容用JavaScript实现
- 提供应用程序可以直接调用的模块,例如 fs、path、http等
- JavaScript无法直接操作底层硬件
1.4.2、Builtin modules 胶水层
1.4.3、底层
- V8:执行JavaScript代码,提供桥梁接口
- libuv:事件循环 事件队列 异步IO
- 第三方模块:zib http c-ares
1.4.1、libuv
Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库
libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;
libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;
libuv :node开发需要一个跨平台的事件库,首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;
1.4.3、c-ares
C语言的异步DNS解析库,可以很方便的和使用者的事件循环统一起来,实现DNS的非阻塞异步解析,libcurl, libevent, gevent, nodejs都在使用。
1.5、Nodejs异步IO和事件驱动
- IO是应用程序的瓶颈,异步IO提升性能无需原地等待返回结果返回,操作系统有对应的实现,
- Nodejs单线程配事件驱动架构及libuv实现异步IO
1.5.1、Nodejs异步IO
同步阻塞
所谓同步,指的是协同步调。既然叫协同,所以至少要有2个以上的事物存在。协同的结果就是:
多个事物不能同时进行,必须一个一个的来,上一个事物结束后,下一个事物才开始。
那当一个事物正在进行时,其它事物都在干嘛呢?
严格来讲这个并没有要求,但一般都是处于一种“等待”的状态,因为通常后面事物的正常进行都需要依赖前面事物的结果或前面事物正在使用的资源。
因此,可以认为,同步更希望关注的是从宏观整体来看,多个事物是一种逐个逐个的串行化关系,绝对不会出现交叉的情况。
所以,自然也不太会去关注某个瞬间某个具体事物是处于一个什么状态。
把这个理论应用的出神入化的非“排队”莫属。凡是在资源少需求多的场景下都会用到排队
所谓阻塞,指的是阻碍堵塞。它的本意可以理解为由于遇到了障碍而造成的动弹不得。
重复调用IO,判断IO是否结束沦陷技术
-
read
-
select:
一个计算机函数,位于头文件#include <sys/select.h> 。该函数用于监视文件描述符的变化情况——读写或是异常。
-
poll:
Linux中的字符设备驱动中的一个函数。Linux 2.5.44版本后,poll被epoll取代。
和select实现的功能差不多,poll的作用是把当前的文件指针挂到等待队列
-
epoll
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
-
kqueue
kueue是在UNIX上比较高效的IO复用技术。
所谓的IO复用,就是同时等待多个文件描述符就绪,以系统调用的形式提供。如果所有文件描述符都没有就绪的话,该系统调用阻塞,否则调用返回,允许用户进行后续的操作。
常见的IO复用技术有select, poll, epoll以及kqueue等等。其中epoll为Linux独占,而kqueue则在许多UNIX系统上存在,包括OS X(好吧,现在叫macOS了。。) -
event ports
跨协作组件的显式调用导致这些组件之间的紧密耦合。
这会降低组件的可维护性、灵活性和可重用性。隐式调用模型解耦了组件,从而减少了组件间的依赖关系。
然而,隐式调用倾向于忽略组件消息兴趣的历史确定性质,导致实现被保护代码污染以强制执行组件的时间顺序协议。
将状态图与隐式调用相结合,可以在没有代码污染的情况下直接实现按时间排序的组件协议,从而为更清洁、更具适应性的组件协作策略提供了潜力。
异步非阻塞
所谓异步,就是步调各异。既然是各异,那就是都不相同。所以结果就是:
多个事物可以你进行你的、我进行我的,谁都不用管谁,所有的事物都在同时进行中。
一言以蔽之,同步就是多个事物不能同时开工,异步就是多个事物可以同时开工。
所谓非阻塞,自然是和阻塞相对,可以理解为由于没有遇到障碍而继续畅通无阻。
期望无需注定判断的非阻塞IO
libuv 是一个跨平台的的基于事件驱动的异步I库,原先为 NodeJS 而写。
但是他提供的功能不仅仅是IO,包括进程、线程、信号、定时器、进程间通信等。
它围绕着事件驱动的异步I/O模型而设计。
这个库提供不仅仅是对不同I/O轮询机制的简单抽象,
还包括: ‘句柄’和‘流’对套接字和其他实体提供了高级别的抽象; 也提供了跨平台的文件I/O和线程功能,以及其他一些东西。
这是一份图表解释了组成libuv的不同组件和它们相关联的子系统:
从上图中我们看到
-
Libuv使用各平台提供的事件驱动模块实现异步(epoll, kqueue, IOCP, event ports)。
他用来支持上层非文件io的模块。libuv把上层的事件和回调封装成io观察者(uv__io_t)放到底层的事件驱动模块。
当事件触发的时候,libuv会执行io观察者中的回调。
-
Libuv实现一个线程池用来支持上层文件io、dns以及用户层耗cpu的任务。Libuv的整体执行架构
1.5.2、Nodejs事件驱动架构
Node.js 事件循环
Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。
Node.js 几乎每一个 API 都是支持回调函数的。
Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。
Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.
事件驱动程序
Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为 webserver 一直接受请求而不等待任何读写操作。(这也称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
整个事件驱动的流程有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。
Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件
1.6、Nodejs单线程
Nodejs单线程指的是主线程是单线程,单线程实现高并发异步非阻塞IO配合事件回调通知
Nodejs单线程不适合CPU密集型业务场景,但是适合IO密集型高并发请求
2、安装Nodejs
官网:https://nodejs.org/en/
中文官网:https://nodejs.org/zh-cn/
中文下载页面:https://nodejs.org/zh-cn/download/current/
2.1、Linux 安装Nodejs
Linux 安装node
官网
mkdir ~/opt
wget https://nodejs.org/dist/v20.17.0/node-v20.17.0-linux-x64.tar.xz
tar -xvf node-v20.17.0-linux-x64.tar.xz -C ~/opt
mv ~/opt/node-v20.17.0-linux-x64 ~/opt/node
终端中输入sudo vim ~/.bashrc
在文档最后追加以下内容
export NODE_HOME=/home/lhz/opt/node
export PATH=$PATH:$NODE_HOME/bin
打开新控制台 输入
node -v
# 搭建环境时通过如下代码将npm设置成淘宝镜像
npm config set registry http://registry.npmmirror.com --global
# 查看镜像的配置结果
npm config get registry
# 使用nrm工具切换淘宝源
npx nrm use taobao
# 如果之后需要切换回官方源可使用
npx nrm use npm
升级npm
npm install -g npm
npm install cnpm -g
npm install yarn -g
npm install pnpm -g
2.2、Windows安装Nodejs
控制台输入node --version
node --version
控制台输入node
node
控制台输入console.log(‘桃李不言下自成蹊’);
console.log('桃李不言下自成蹊');
# 搭建环境时通过如下代码将npm设置成淘宝镜像
npm config set registry http://registry.npmmirror.com --global
# 查看镜像的配置结果
npm config get registry
# 使用nrm工具切换淘宝源
npx nrm use taobao
升级 npm
npm install -g npm
npm install cnpm -g
npm install yarn -g
npm install pnpm -g
3.1、使用WebStorm创建Nodejs项目并运行Nodejs代码
3.2、VSCode运行Nodejs代码
3.2.1、初始化Nodejs项目
# Linux
mkdir code
cd code
sudo npm init --yes
# Linux
mkdir code
cd ./project01
npm init --yes
返回
Wrote to D:\dev\node\code\project01\package.json:
{"name": "project01","version": "1.0.0","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","description": ""
}
编写index.js文件
console.log('我爱你中国,亲爱的母亲');
控制台执行:node index.js
node index.js
3.2.2、VScode安装扩展Code Runner
3.3、Node的注意事项(了解)
nodejs : ECMAScript + 核心的api(重点) . 没有 DOM、 BOM
4、Nodejs核心模块API使用
4.1、模块化
4.1.1、模块化历程
传统开发常见问题导致项目难以维护不便于复用
- 命名冲突和污染
- 代码冗余,过多的无效请求
- 文件间依赖关系纷杂
模块化是指将一个大的程序文件,拆分为许多小的文件(模块),然后将小的文件组合起来。
- 防止命名冲突
- 代码复用
- 高维护性
模块化开发是一种管理方式,是一种生产方式,一种解决问题的方案,一个模块就是实现特定功能的文件,有了模块,想要什么功能,就加载什么模块
模块开发需要遵循一定的规范,否则就都乱套了,因此,才有了后来大家熟悉的AMD规范,CMD规范
ES6之前本身没有模块化,社区衍生出模块化产品
- CommonJS ===> NodeJS、Browserify
- AMD ===> RequireJS
- CMD ===> SeazJS
CommonJS规范
CommonJS 是以在浏览器环境之外构建 javaScript 生态系统为目标而产生的写一套规范,
主要是为了解决 javaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行,该规范的主要内容是,
模块必须通过 module.exports 导出对外的变量或者接口,
通过 require() 来导入其他模块的输出到当前模块的作用域中;
目前在服务器和桌面环境中,node.js 遵循的是 CommonJS 的规范;
CommonJS 对模块的加载时同步的;
- 模块引用
- 模块标识
- 模块定义
module属性
- 任意js文件就是一个模块,可以直接使用module属性
- id:返回模块标识符,一般是一个据对路径
- filename:返回文件模块决定路径
- loaded:返回布尔值,表示模块是否加载完成
- parent:返回对象存放调用当前模块的模块
- children:返回数组,存放当前模块调用其他模块
- exports:返回当前模块需要暴露的内容
- paths:返回数组,存放不同目录下的node_module位置
require属性
- 基本功能:读入并且执行一个模块文件
- reslove:模块文件据对路径
- extensions:依据不同后缀名执行解析操作
- main:返回主模块对象
AMD
AMD 即Asynchronous Module Definition,中文名是“异步模块定义”的意思,它采用异步方式加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行
一般来说,AMD是 RequireJS 在推广过程中对模块定义的规范化的产出,因为平时在开发中比较常用的是require.js进行模块的定义和加载,
一般是使用define来定义模块,使用require来加载模块
AMD 主要是为前端 js 的表现指定的一套规范;而 CommonJS 是主要为了 js 在后端的表现制定的,它不适合前端;
AMD 也是采用 require() 语句加载模块的,但是不同于 CommonJS ,它有两个参数;require([‘模块的名字’],callBack);requireJs 遵循的就是 AMD 规范;
// 定义模块
define('math',['jquery'], function ($) {//引入jQuery模块return {add: function(x,y){return x + y;}};
});
// 调用模块
require(['jquery','math'], function ($,math) {console.log(math.add(10,100));//110
});
CMD
CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,同时,CMD是在SeaaJS推广的过程中形成的,
CMD和AMD要解决的都是同个问题,在使用上也都很像,只不过两者在模块定义方式和模块加载时机上有所不同
CMD 也是通过异步的方式进行模块的加载的,不同于 AMD 的是,CMD 的加载是按照就近规则进行的,
AMD 依赖的是前置;CMD 在加载的使用的时候会把模块变为字符串解析一遍才知道依赖了哪个模块;
// 定义模块 myModule.js
define(function(require, exports, module) {var $ = require('jquery.js')$('div').addClass('active');exports.data = 1;
});// 加载模块
seajs.use(['myModule.js'], function(my){var star= my.data;console.log(star); //1
});
ES6中的模块化
在ES6没有出来之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种,前者用于服务器,后者用于浏览器,
ES module 在语言标准的层面上,实现了模块功能,而且相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案
ES module 中的模块化有一个比较大的特点,就是实现尽量的静态化
4.1.2、前端模块化
m01.js
export const slogan = '桃李不言下自成蹊';
export const love = function () {console.log('我爱你中国,亲爱的母亲');
}
m01.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模块化</title>
</head><body></body></html>
<script type="module">import * as m01 from './src/js/m01.js'console.log(m01.slogan);m01.love()
</script>
m02.js
const slogan = '桃李不言下自成蹊';
const love = function () {console.log('我爱你中国,亲爱的母亲');
}
export{slogan,love}
m02.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模块化</title>
</head><body></body></html>
<script type="module">import * as m02 from './src/js/m02.js'console.log(m02.slogan);m02.love()// 解构赋值import {slogan,love} from './src/js/m02.js';console.log(slogan);love()
</script>
m03.js
export default{slogan : '桃李不言下自成蹊',love :function () {console.log('我爱你中国,亲爱的母亲');}
}
m03.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模块化</title>
</head><body></body></html>
<script type="module">import * as m03 from './src/js/m03.js'console.log(m03.default.slogan);m03.default.love()// 解构赋值import {default as m003} from './src/js/m03.js';console.log(m003.slogan);m003.love()// 针对默认暴露 简便形式import m30 from './src/js/m03.js';console.log(m30.slogan);m30.love()
</script>
app.js
import * as m001 from "./m01.js"
import * as m002 from "./m02.js"
import {default as m300} from "./m03.js"
window.console.log(m001.slogan);
m001.love();
window.console.log(m002.slogan);
m002.love();
window.console.log(m300.slogan);
m300.love();
app.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模块化</title>
</head><body></body></html>
<script src="./src/js/app.js" type="module" charset="utf-8"></script>
由于兼容性问题,需要将高版本js代码转化为兼容性较好的低版本代码
使用babel可以轻松的进行转换
安装三个工具:babel-cli babel-preset-env browserify(webpack)
首先使用 init 初始化 npm 包文件
npm init --yes
安装babel工具
npm i babel-cli babel-preset-env browserify -D
编译(js为源文件夹 dist/js 为目标文件夹,会自动生成)
–presets=babel-preset-env /可以单独配置babel配置文件实现
npx babel src/js -d dist/js --presets=babel-preset-env
browserify
app.js中 require 浏览器还是不识别,需要再次转换
npx browserify dist/js/app.js -o dist/bundle.js
npm init --yes
npm i babel-cli babel-preset-env browserify -D
npx babel src/js -d dist/js --presets=babel-preset-env
npx browserify dist/js/app.js -o dist/bundle.js
bundle.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>bundle</title>
</head>
<body></body>
</html>
<script src="dist/bundle.js" type="text/javascript" charset="utf-8"></script>
引入npm模块
npm i jquery
jquery.js
// const $ = require('jquery')
import $ from 'jquery'
$('body').css('background', '#FA6060');
npx babel src/js -d dist/js --presets=babel-preset-env
npx browserify dist/js/jquery.js -o dist/jquery.js
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>jquery</title>
</head>
<body></body>
</html>
<script src="./dist/jquery.js"></script>
4.1.3、Nodejs模块化
m01.js
const slogan = '桃李不言下自成蹊';
const love = () => {return '我爱你中国,亲爱的母亲';
}
module.exports = {slogan: slogan,love: love
}
r01.js
const m01 = require('./src/js/m01');
console.log(m01.slogan);
console.log(m01.love());
m02.js
console.log(module);
r02.js
const m02 = require('./src/js/m02');
m03.js
exports.name = 'lhz'
r03.js
const m03 = require('./src/js/m03');
console.log(m03);
m04.js
console.log('我嫁人了');
r04.js
const m04 = require('./src/js/m04');
console.log('我娶你');
m05
console.log('我嫁人了');
let date = new Date();
while (new Date() - date < 6000) {}
r05.js
const m05 = require('./src/js/m05');
console.log('我娶你');
4.2、Nodejs全局对象
- 与浏览器中的window不完全相同
- Nodejs全局对象global
4.3、Nodejs全局变量
- __filename:返回正在执行脚本文件的绝对路径
- __dirame:返回正在执行脚本文件所在目录的(相对路径)
- time类函数:执行顺序与事件循环间的关系
- process:提供与当前进程互动的接口
- require:加载模块
- exports:模块导出
- module:模块导出
- this:
module.exports 初始值为一个空对象 {}exports 是指向的 module.exports 的引用require() 返回的是 module.exports 而不是 exports
4.3.1、process
// const fs = require('fs');console.log(process.memoryUsage());
console.log(process.cpuUsage());
console.log(process.cwd());
console.log(process.version);
console.log(process.versions);
console.log(process.arch);
console.log(process.env.Path);
console.log(process.env.USERPROFILE);
console.log(process.platform);console.log(process.argv);
console.log(process.pid);
// 当前程序运行时间
console.log(process.uptime());// 事件
process.on('exit',function (code) {console.log('exit : ' + code)
});process.on('beforeExit',function (code) {console.log('beforeExit : ' + code)
});//{
// rss: 18563072,
// heapTotal: 4321280,
// heapUsed: 3440000,
// external: 212402,
// arrayBuffers: 11146
// }
// rss: (Resident Set Size)操作系统分配给进程的总的内存大小。
// heapTotal:堆的总大小,包括3个部分,
// 已分配的内存,用于对象的创建和存储,对应于heapUsed
// 未分配的但可用于分配的内存
// 未分配的但不能分配的内存,例如在垃圾收集(GC)之前对象之间的内存碎片
// heapUsed: 已分配的内存,即堆中所有对象的总大小,是heapTotal的子集。
// external: 进程使用到的系统链接库所占用的内存
// arrayBuffers:
4.3.2、path
- basename()获取路径中的基础名称
- dirname()获取路径中的目录名
- extname()获取后缀名
- isAbsolute()获取路径是否为绝对路径
- join()路径拼接
- reslove()返回绝对路径
- parse()解析路径
- formart()序列化路径
- normalize()规范化路径
5、Nodejs创建HTTP服务
5.1、Nodejs创建HTTP服务
mkdir httpServer
cd httpServer
npm init --yes
新建文件node.js,编写代码如下:
// 引入http模块
var http = require('http');// 使用http模块创建httpServer
var server = http.createServer();// 处理HTTP请求
server.on('request', function (request, response) {// 设置响应头response.writeHead(200, { 'Content-type': 'text/html;charset=utf-8' });// 给客户端发送字符串response.write('<h3>我爱你中国<h3>');// 结束响应 (关闭输出流)response.end();
});// 端口监听 (启动的服务)
server.listen(6633, function () {console.log('服务已启动,请访问http://127.0.0.1:6633');
});
node app.js
5.2、nodemon
全局安装nodemon
npm i nodemon -g
在项目目录以开发模式安装nodemon
npm i nodemon -D
编写package.json文件,在scripts中增加以下内容:
"start": "nodemon app.js"
修改后的package.json文件内容如下:
{"name": "httpserver","version": "1.0.0","description": "","main": "index.js","scripts": {"start": "nodemon app.js","test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","devDependencies": {"nodemon": "^2.0.12"}
}
vue
使用vite创建vue工程
npm create vite@latest -- --template vue-appcd vue-app
npm install
npm run dev
1、chap01
-
文本插值
<script setup lang="ts"> import {ref} from "vue"; // ref 使用该函数装饰响应式的值 const slogan = ref('以吾辈之青春,捍卫盛世之华夏'); const msg = ref('欢迎台湾同胞回家'); const html = ref('<a href="https://space.bilibili.com/480308139/">李昊哲小课</a>'); const count = ref(0); </script><template><!--组件index.html -> main.ts -> chap01/HelloLhz.vue -> chap01/LhzA.vue--><h1>文本插值</h1><div>{{slogan}}</div><div v-text="msg"></div><!-- v-text = innerText --><div v-text="html"></div><!-- v-html = innerHTML --><div v-html="html"></div><div v-text="count"></div> </template><style scoped></style>
-
事件处理
<script setup lang="ts"> import {ref} from "vue"; // ref 使用该函数装饰响应式的值 const slogan = ref('以吾辈之青春,捍卫盛世之华夏'); const msg = ref('欢迎台湾同胞回家'); const html = ref('<a href="https://space.bilibili.com/480308139/">李昊哲小课</a>'); const count = ref(0); const getMsg = () => {window.alert(msg.value); } const fun01 = () => {window.alert(1); } const fun02 = () => {window.alert(2); } const fun03 = (e) => {console.log(e); } const accumulation = () => {count.value++; } </script><template><h1>事件处理</h1><div v-text="msg"></div><!-- 默认情况下调用无参函数不加括号 --><button type="button" v-on:click="getMsg">你过来呀</button><!-- 默认情况下调用无参函数也可以加括号 --><button type="button" v-on:click="getMsg()">你过来呀()</button><!-- @动作指令 语法糖 --><button type="button" @click="getMsg">语法糖</button><!-- 同一个动作指令调同时调用多个函数的时候 函数需要加括号 --><button type="button" @click="fun01(),fun02()">多事件绑定</button><button type="button" @click="fun03($event)">事件对象参数</button><button type="button" @click="count++" v-text="count"></button><button type="button" @click="accumulation" v-text="count"></button><!-- v-once 表示其内容只会被渲染一次 --><div><span v-text="count" v-once></span></div> </template><style scoped></style>
-
事件修饰符
<script setup lang="ts"> const out = () => {window.alert("out_box"); } const inner = () => {window.alert("inner_box"); } const go = () => {window.alert("once"); }</script><template> <div><h1>事件修饰符</h1><!--prevent 取消事件默认行为stop 阻止事件冒泡once 只执行一次 仅一次生效--><div><form action="https://www.baidu.com/s?" method="get"><input type="search" name="wd" id=""><input type="submit" value="千度以下,你就知道" @click.prevent></form></div><div id="out_box" @click="out"><div id="inner_box" @click.stop="inner"><!-- 链式调用 方法进执行一次 但 prevent 仅一次生效 --><a href="https://space.bilibili.com/480308139/" @click.prevent.once="go">李昊哲-小课</a><br><!-- 分开写 一切正常 --><a href="https://space.bilibili.com/480308139/" @click.prevent @click.once="go">李昊哲</a></div></div> </div> </template><style scoped> #out_box{margin-top: 30px;width: 450px;height: 450px;background-color: #4365c3;text-align: center;position: relative;//color: #ffffff; } #inner_box{width: 300px;height: 300px;background-color: #929854;position: absolute;left: 75px;top: 75px; } </style>
-
属性绑定
<script setup lang="ts"> // 引入图片静态资源 import logo from '../../assets/logo.png'; import {ref} from "vue";const alt = ref('vue logo') const title = ref('忘记历史等于背叛'); const width = ref(600); const id = ref('img-attr'); </script><template> <h1>属性绑定</h1><img :src="logo" :alt="alt" :title="title" :width="width" :id="id"/> </template><style scoped></style>
-
动态属性
<script setup lang="ts"> // 引入图片静态资源 import logo from '../../assets/logo.png'; import coding from '../../assets/coding.jpg'; import {ref} from "vue";const alt = ref('vue logo') const title = ref('忘记历史等于背叛'); const figure = ref(600); const id = ref('img-attr'); const woh = ref('width'); const changeAttr = () => {woh.value = woh.value === 'width' ? 'height' : 'width'; } </script><template><h1>动态属性</h1><img :alt="alt" :src="coding" :title="title" :[woh]="figure" :id="id" @click="changeAttr">> </template><style scoped></style>
2、chap02
-
v-show
<script setup lang="ts"> import computer_room from '../../assets/computer_room.png'; import {ref} from "vue";const alt = ref('computer_room'); const figure = ref(600); const title = ref('忘记历史等于背叛'); const condition = ref(true) </script><template><h1 @click="condition = !condition">v-show</h1><!-- v-show 控制元素是否显示 相当于 在css样式中使用 display; --><!-- v-show 值为 true 相当于 在css样式中使用 display: block; --><!-- v-show 值为 false 相当于 在css样式中使用 display: none; --><img :src="computer_room" :alt="alt" :width="figure" :title="title" v-show="condition"/> </template><style scoped></style>
-
v-if
<script setup lang="ts"> import computer_room from '../../assets/computer_room.png'; import {ref} from "vue";const alt = ref('computer_room'); const figure = ref(600); const title = ref('忘记历史等于背叛'); const condition = ref(true) const gender = ref('男') const changeGender = () => {condition.value = !condition.valuegender.value = condition.value ? '男' : '女' } const weekDay = ref(3); </script><template><h1 @click="condition = !condition">v-if</h1><!-- v-if 控制元素是否显示 相当于 dom是否存在 --><img :src="computer_room" :alt="alt" :width="figure" :title="title" v-if="condition"/><h1 @click="changeGender" v-text="gender"></h1><h1 v-if="condition">男性</h1><h1 v-else>女性</h1><span v-if="weekDay % 7 === 1">星期一</span><span v-else-if="weekDay % 7 === 2">星期二</span><span v-else-if="weekDay % 7 === 3">星期三</span><span v-else-if="weekDay % 7 === 4">星期四</span><span v-else-if="weekDay % 7 === 5">星期五</span><span v-else-if="weekDay % 7 === 6">星期六</span><span v-else>星期日</span> </template><style scoped></style>
-
v-for
<script setup lang="ts"> import {reactive} from "vue";const names = reactive(['李昊哲', '大美丽', '李胜龙', '小可爱']); const person = reactive({name: '李昊哲',age: 43,gender: true })const persons = reactive([{id: 1,name: '李昊哲',age: 35,gender: true,}, {id: 2,name: '大美丽',age: 39,gender: false,}, {id: 3,name: '李胜龙',age: 39,gender: true,}, {id: 4,name: '小可爱',age: 27,gender: false,} ]); </script><template><h1>v-for</h1><ul><!-- 第一个参数是列表元素 第二个参数是列表索引 --><li v-for="(name,index) in names" v-text="name" :key="name"></li></ul><ul><!-- 第一个参数是列表元素 第二个参数是列表索引 --><li v-for="(name,index) in names" v-text="names[index]" :key="name + index"></li></ul><!-- 第一个参数是对象属性值 第二个参数是对象属性名 --><div v-for="(value,field) in person" v-text="field + ':' + value" :key="field + ':' + value"></div><table><thead><tr><th>id</th><th>姓名</th><th>年龄</th><th>性别</th></tr></thead><tbody><tr v-for="(person,index) in persons" :key="field"><td v-for="(value,filed) in person" v-text="value"></td></tr></tbody></table><table><thead><tr><th>id</th><th>姓名</th><th>年龄</th><th>性别</th></tr></thead><tbody><tr v-for="(person,index) in persons" :key="field"><td v-text="person.id"></td><td v-text="person.name"></td><td v-text="person.age"></td><td v-text="person.gender === true? '男': '女'"></td></tr></tbody></table> </template><style scoped> ul > li {list-style: none; }table td {text-align: center;padding: 10px 30px; } </style>
-
计算属性
<script setup lang="ts"> import {computed, reactive, ref} from "vue";const slogan = ref('友谊第一,比赛第二'); const time = ref(0); const countdown = setInterval(() => {time.value++;if (time.value === 10) {disabled.value = true;clearInterval(countdown);} }, 1000);const team = reactive({china: 0,korea: 0 }); const result = ref(computed(() => {if (team.china > team.korea) {return '中国队领先'} else if (team.china < team.korea) {return '韩国队领先'} else {return '势均力敌';} })) const disabled = ref(false); </script><template><h1>计算属性</h1><h1 v-text="slogan"></h1><h2>比赛时间:<span v-text="time"></span></h2><h2>直播播报:<span v-text="result"></span></h2><h2>中国队进球数:<span v-text="team.china"></span><button type="button" @click="team.china++" :disabled="disabled">点击中国队进一球</button></h2><h2>韩国队进球数:<span v-text="team.korea"></span><button type="button" @click="team.korea++" :disabled="disabled">点击韩国队进一球</button></h2> </template><style scoped></style>
-
侦听器
<script setup lang="ts"> import {ref, watch, watchEffect} from "vue";const msg = ref('铭记历史勿忘国耻'); watchEffect(() => {console.log('watchEffect msg >>> ' + msg.value) });// 第一个参数为侦听的对象 watch(msg, (value, oldValue, onCleanup) => {// 第一个参数是变化后的值// 第二个参数是变化前的值console.log(`value >>> ${value} \t oldValue >>> ${oldValue}`); }, {immediate: true,// deep:当需要对对象等引用类型数据进行深度监听时,设置deep: true,默认值是false。// immediate:默认情况下watch是惰性的,设置immediate: true时,watch会在初始化时立即执行回调函数一次。// flush:控制回调函数的执行时机,。它可设置为 pre、post 或 sync。// pre:默认值,当监听的值发生变更时,优先执行回调函数(在dom更新之前执行)。// post:dom更新渲染完毕后,执行回调函数。// sync:一旦监听的值发生了变化,同步执行回调函数(建议少用) }); </script><template><input type="text" name="" id="" v-model="msg"><h1 v-text="msg"></h1> </template><style scoped></style>
-
侦听器案例
<script setup lang="ts"> import {computed, reactive, ref, watch} from "vue";const slogan = ref('友谊第一,比赛第二'); const time = ref(0); const countdown = setInterval(() => {time.value++;if (time.value === 10) {disabled.value = true;clearInterval(countdown);} }, 1000);const team = reactive({china: 0,korea: 0 }); const result = ref('势均力敌') watch(team, (value, oldValue, onCleanup) => {if (team.china > team.korea) {result.value = '中国队领先'} else if (team.china < team.korea) {result.value = '韩国队领先'} else {result.value = '势均力敌';} }, {deep: true}) const disabled = ref(false); </script><template><h1>计算属性</h1><h1 v-text="slogan"></h1><h2>比赛时间:<span v-text="time"></span></h2><h2>直播播报:<span v-text="result"></span></h2><h2>中国队进球数:<span v-text="team.china"></span><button type="button" @click="team.china++" :disabled="disabled">点击中国队进一球</button></h2><h2>韩国队进球数:<span v-text="team.korea"></span><button type="button" @click="team.korea++" :disabled="disabled">点击韩国队进一球</button></h2> </template><style scoped></style>
3、chap03
表单操作
-
v-model
<script setup lang="ts"> import {ref} from "vue";const msg = ref('山河统一,解放台湾'); const male = ref(1); const female = ref(0); const checked = ref(true); const hobbies = ref(["swimming", "skiing"]); const hometown = ref('jilin'); const fruits = ref(['pear']); </script><template><h1>v-model</h1><input type="text" name="" id="" v-model="msg" /><h1 v-text="msg"></h1>性别:<label for="male">男:<input type="radio" name="gender" id="male" v-model="male" /></label> <label for="female">女:<input type="radio" name="gender" id="female" v-model="female" :checked="checked" /></label><br><label for="remember">记住我:<input type="checkbox" name="remember" id="remember" :checked="checked" /></label><h3>多选按钮</h3>爱好: <input type="checkbox" id="swimming" name="hobby" value="swimming" v-model="hobbies"> <label for="running">跑步</label><input type="checkbox" id="running" name="hobby" value="running" v-model="hobbies"> <label for="skiing">滑雪</label><input type="checkbox" id="skiing" name="hobby" value="skiing" v-model="hobbies"><br><h3>单选下拉列表</h3>籍贯: <select name="hometown" id="hometown" v-model="hometown"><option value="beijing">北京</option><option value="shanghai">上海</option><option value="jilin">吉林</option></select><h3>多选下拉列表</h3>水果: <select name="fruits" id="fruits" multiple v-model="fruits"><option value="banana">香蕉</option><option value="apple">苹果</option><option value="pear">梨</option></select> </template><style scoped></style>
4、chap04
父子组件
<script setup lang="ts">
const props = defineProps(['person','msg'])
const {msg} = props
const {person} = props
</script><template><!-- 父子组件 defineProps 传值 子组件 --><h1 v-text="props.msg"></h1><h1 v-text="props.person.realName"></h1><h1 v-text="props.person.slogan"></h1><h1 v-text="msg"></h1><h1 v-text="person.realName"></h1><h1 v-text="person.slogan"></h1>
</template><style scoped></style>
-
defineProps
<script setup lang="ts"> const props = defineProps(['person','msg']) const {msg} = props const {person} = props </script><template><!-- 父子组件 defineProps 传值 子组件 --><h1 v-text="props.msg"></h1><h1 v-text="props.person.realName"></h1><h1 v-text="props.person.slogan"></h1><h1 v-text="msg"></h1><h1 v-text="person.realName"></h1><h1 v-text="person.slogan"></h1> </template><style scoped></style>
-
useAttrs
<script setup lang="ts"> import {useAttrs} from "vue";defineOptions({inheritAttrs: false, })const attrs = useAttrs() const {msg} = attrs const {person} = attrs </script><template><!-- 父子组件 useAttrs 传值 子组件 --><h1 v-text="attrs.msg"></h1><h1 v-text="attrs.person.realName"></h1><h1 v-text="attrs.person.slogan"></h1><h1 v-text="msg"></h1><h1 v-text="person.realName"></h1><h1 v-text="person.slogan"></h1> </template><style scoped></style>
-
defineEmits
<script setup lang="ts"> import LhzE from "./LhzE.vue"; import {reactive, ref} from "vue";const msg = ref('忘记历史等于背叛'); const person = reactive({realName: '李昊哲',slogan: '河山统一,解放台湾' }); const updateName = (value) => {person.realName = value; } </script><template><h1>父组件:<span v-text="msg"></span></h1><h1>父组件:<span v-text="person.realName"></span></h1><h1>父组件:<span v-text="person.slogan"></span></h1><hr><!-- 父子组件 defineProps 传值 父组件 --><lhz-e :person="person" :msg="msg" @update="updateName"/> </template><style scoped></style>
<script setup lang="ts"> import {ref} from "vue";const props = defineProps(['person', 'msg']) const {msg} = props const {person} = props const newName = ref(''); const emit = defineEmits() const updateName = () => {// 第一个参数为 父组件接收子组件的动作指令// 第二个参数为 子组件向父组件发送的数据emit('update', newName) } </script><template>S<!-- 父子组件 defineProps 传值 子组件 --><input type="text" name="" id="" autocomplete="off" v-model="newName" @input="updateName"><!-- 父子组件 defineProps 传值 子组件 --><h1>子组件:<span v-text="msg"></span></h1><h1>子组件:<span v-text="person.realName"></span></h1><h1>子组件:<span v-text="person.slogan"></span></h1> </template><style scoped></style>
-
provide 与 inject
const slogan = Symbol(); const obj = Symbol(); const msg = Symbol(); const location = Symbol(); export {slogan,obj,msg,location }
<script setup lang="ts"> import LhzM from "./LhzM.vue"; import {provide, reactive, ref} from "vue"; import {slogan, obj, msg, location} from "./keys"const my_slogan = ref('河山一统'); const my_obj = reactive({slogan: '解放台湾' });const my_msg = () => {return my_slogan; } // provide('slogan', my_slogan); // provide('obj', my_obj); // provide('msg', my_msg);provide(slogan, my_slogan); provide(obj, my_obj); provide(msg, my_msg); provide(location, {my_slogan, my_obj, my_msg}); </script><template><h1>LhzL</h1><lhz-m/> </template><style scoped></style>
<script setup lang="ts"> import LhzN from "./LhzN.vue"; </script><template><h1>LhzM</h1><lhz-n/> </template><style scoped></style>
<script setup lang="ts"> import {inject, ref} from "vue"; import {slogan, obj, msg,location} from "./keys" // const new_slogan = inject('slogan') // const new_obj = inject('obj') // const new_msg01 = inject('msg')() // const new_msg02 = inject('msg') // const content = ref(new_msg02())const new_slogan = inject(slogan) const new_obj = inject(obj) const new_msg01 = inject(msg)() const new_msg02 = inject(msg) const content = ref(new_msg02()) const {my_slogan,my_obj,my_msg} = inject(location) const result = ref(my_msg()) </script><template><h1>LhzN</h1><div v-text="new_slogan"></div><div v-text="new_obj"></div><div v-text="new_obj.slogan"></div><div v-text="new_msg01"></div><div v-text="content"></div><hr><div v-text="my_slogan"></div><div v-text="my_obj"></div><div v-text="my_obj.slogan"></div><div v-text="result"></div> </template><style scoped></style>
-
选项卡案例
<script setup lang="ts"> import LhzTabBtn from "./LhzTabBtn.vue"; import LhzTabContent from "./LhzTabContent.vue"; import {ref} from "vue";const index = ref(0); const changeTab = (param) => {index.value = param; } </script><template><lhz-tab-btn @changeTab="changeTab"/><lhz-tab-content :tabIndex="index"/> </template><style scoped> </style>
<script setup lang="ts"> import {reactive} from "vue";const lis = reactive([{'title': '商品介绍','classList': ['current'],}, {'title': '规格包装','classList': [],}, {'title': '售后保障','classList': [],}, {'title': '商品评价(66)','classList': [],}, {'title': '手机社区','classList': [],} ]); const emit = defineEmits(['changeTab']); const change = (index) => {// 遍历列表中中的所有元素outer:for (const item of lis) {// 获取列表中当前元素的的 classList 属性let class_list = item.classList;// 遍历 classList 即当前元素的css样式列表for (let i = 0; i < class_list.length; i++) {// 获取当前元素的css样式列表if (class_list[i] === 'current') {// 如果当前的 css 样式 列表中 存在 current 样式 则将 current 从当前列表移除class_list.splice(i, 1);// 结束外出循环break outer;}}}// 被点击的元素添加 current 样式lis[index].classList.push('current');// 将被点击的元素的 index 值 向上发射emit('changeTab', index); } </script><template><!-- 选项卡按钮 --><div class="tab-btn"><ul><li v-for="(item,index) in lis" :key="item.title + index" v-text="item.title" :class="item.classList" @click="change(index)"></li></ul></div> </template><style scoped> .tab-btn {width: 990px;border-bottom: 1px solid #e4393c;color: #666;cursor: pointer;position: absolute;left: 0;top: 0; }ul > li {list-style: none;float: left;font-size: 14px;width: 160px;height: 38px;line-height: 38px;text-align: center; }.current {background-color: #e4393c;color: #fff; } </style>
<script setup lang="ts"> import {reactive, useAttrs, watchEffect} from "vue";const contents = reactive([{'title': '商品介绍',isShow: true}, {'title': '规格包装',isShow: false}, {'title': '售后保障',isShow: false}, {'title': '商品评价(66)',isShow: false}, {'title': '手机社区',isShow: false} ]);const attrs = useAttrs(); watchEffect(() => {for (const index in contents) {contents[index].isShow = attrs.tabIndex === parseInt(index)} }) </script><template><div class="tab-content"><div v-for="(content,index) in contents" :key="content.title + ' ' + index" v-text="content.title" v-show="content.isShow"></div></div> </template><style scoped> .tab-content {width: 100%;color: #666;background-color: #ffffff;position: absolute;top: 80px;left: 0;padding: 30px;font-size: 66px; } </style>
5、chap05
插槽
-
slot
<script setup lang="ts"> import LhzA from "./LhzA.vue"; import {ref} from "vue"; const username = ref('李胜龙'); const love = () => {username.value = '李昊哲'; } </script><template><lhz-a><template v-slot:nav><!-- 具名插槽 --><div>头部导航</div></template><template v-slot:default><!-- 默认插槽 --><input type="text" autocomplete="off" v-model="username"><button type="button" @click="love">love</button></template><template #footer><!-- 具名插槽缩写 --><div>友情链接</div></template><template #lhz-aa/><template #lhz-bb="{names}"><ul><li v-for="(name,index) in names" v-text="name"></li></ul></template><template #lhz-cc="{item}"><span v-text="item"></span></template></lhz-a> </template><style scoped></style>
<script setup lang="ts"> import {reactive} from "vue";const names = reactive(['李昊哲', '李大宝', '李胜龙']); </script><template><slot name="nav"/><slot/><h1>我是LhzA</h1><slot/><slot name="footer"/><hr><ul><li v-for="(name,index) in names" v-text="name"></li></ul><hr><slot name="lhz-aa"><ul><li v-for="(name,index) in names" v-text="name"></li></ul></slot><slot name="lhz-bb" :names="names"/><ul><li v-for="(item,index) in names"><slot name="lhz-cc" :item="item"/></li></ul> </template><style scoped></style>
6、chap06
步骤:
-
安装路由
npm install vue-router@4
-
准备视图组件
- HomeView.vue
- AboutView.vue
-
编写路由规则
import {createMemoryHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue"; import AboutView from "../../views/chap06/AboutView.vue";const routes = [{path: '/home', component: HomeView},{path: '/about', component: AboutView}, ]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
-
在
main.ts
或者main.js
文件中引入了并使用路由规则import { createApp } from 'vue' import './style.css' import router from "./router/chap06/router.ts"; import App from './App.vue' const app = createApp(App) app.use(router) app.mount('#app')
-
在组件中编写路由跳转按钮
<script setup lang="ts"> import {useRoute} from "vue-router";const route = useRoute() </script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link><router-view/> </template><style scoped></style>
路由模式
hash模式
memory模式
html5模式
router.ts 路由配置文件
import {createMemoryHistory, createWebHistory,createWebHashHistory,createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";const routes = [{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
处理404
-
准备404页面
<script setup lang="ts"></script><template><h1>NotFound</h1> </template><style scoped></style>
-
router.ts 路由配置文件
import {createMemoryHistory, createWebHistory,createWebHashHistory,createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue"; import AboutView from "../../views/chap06/AboutView.vue"; import NotFoundView from "../../views/chap06/NotFoundView.vue";const routes = [// 处理404{path:'/:pathMatch(.*)*',component:NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView}, ]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes, }) export default router
动态路由传参
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory,createWebHashHistory,createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";const routes = [// 处理404{path:'/:pathMatch(.*)*',component:NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {computed, reactive, ref} from "vue";
import {useRoute} from "vue-router";const orders = reactive([{id: '1',productName: '商品1'},{id: '2',productName: '商品2'},{id: '3',productName: '商品3'},{id: '4',productName: '商品4'},{id: '5',productName: '商品5'},
]);
const productName = ref(computed(() => {const order = orders.find(item => item.id === useRoute().params.id);if (order) {return order.productName;} else {return null;}
}));
</script><template><h1>Order</h1><h1 v-text="productName"></h1>
</template><style scoped></style>
嵌套路由
<script setup lang="ts"></script><template><h1>UserLoginView</h1>
</template><style scoped></style>
<script setup lang="ts"></script><template><h1>UserDetailView</h1>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink>
</template><style scoped></style>
命名路由与别名
<script setup lang="ts"></script><template><h1>TestA</h1>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";
import TestA from "../../views/chap06/TestA.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},{path: '/testA',// 命名理由name: 'nameA',// 路由别名 指的是路径的别名alias: ['/ta1', '/ta2'],component: TestA},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{name:'nameA'}">Go to nameA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink>
</template><style scoped></style>
路由传参
params
<script setup>
import {computed, ref} from "vue";
import {useRoute} from "vue-router";const id = ref(computed(() => {return useRoute().params.id;
}));
</script><template><h1>TestB</h1><h1 v-text="id"></h1>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";
import TestA from "../../views/chap06/TestA.vue";
import TestB from "../../views/chap06/TestB.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},{path: '/testA',// 命名理由name: 'nameA',// 路由别名 指的是路径的别名alias: ['/ta1', '/ta2'],component: TestA},{// 路由传参name: 'nameB',path: '/testB/:id',component: TestB},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink><br/><!-- 路由传参 --><router-link :to="{ name: 'nameB', params: { id: '3' }}">Go to nameB</router-link>
</template><style scoped></style>
query
<script setup>
import {computed, ref} from "vue";
import {useRoute} from "vue-router";const id = ref(computed(() => {return useRoute().params.id;
}));
</script><template><h1>TestB</h1><h1 v-text="id"></h1>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";
import TestA from "../../views/chap06/TestA.vue";
import TestB from "../../views/chap06/TestB.vue";
import TestC from "../../views/chap06/TestC.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},{path: '/testA',// 命名理由name: 'nameA',// 路由别名 指的是路径的别名alias: ['/ta1', '/ta2'],component: TestA},{// 路由传参name: 'nameB',path: '/testB/:id',component: TestB},{// 路由传参name: 'nameC',path: '/testC',component: TestC},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink><br/><!-- 路由传参 --><router-link :to="{ name: 'nameB', params: { id: '3' }}">Go to nameB</router-link><router-link :to="{ name: 'nameC', query: { id: '3' }}">Go to nameC</router-link>
</template><style scoped></style>
重定向
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";
import TestA from "../../views/chap06/TestA.vue";
import TestB from "../../views/chap06/TestB.vue";
import TestC from "../../views/chap06/TestC.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},{path: '/testA',// 命名理由name: 'nameA',// 路由别名 指的是路径的别名alias: ['/ta1', '/ta2'],component: TestA},{// 路由传参name: 'nameB',path: '/testB/:id',component: TestB},{// 路由传参name: 'nameC',path: '/testC',component: TestC},{path: '/test_redirect',// redirect: '/testA',// redirect: '/ta1',redirect: {name: 'nameA'},},{name: 'redirect_with_query',path: '/redirect_with_query',redirect: {name: 'nameC'},},{name: 'redirect_with_params',path: '/redirect_with_params/:id',redirect: to => {console.log(to)// 方法接收目标路由作为参数// return 重定向的字符串路径/路径对象// return {path: '/testC', query: {id: to.params.id}}return {name: 'nameB', params: {id: to.params.id}}},},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink><br/><!-- 路由传参 --><router-link :to="{ name: 'nameB', params: { id: '3' }}">Go to nameB</router-link><router-link :to="{ name: 'nameC', query: { id: '3' }}">Go to nameC</router-link> <!-- redirect 重定向 --><RouterLink :to="{path: '/test_redirect'}">Go to test_redirect</RouterLink> <router-link :to="{ name: 'redirect_with_query', query: { id: '3' }}">Go to redirect_with_query</router-link> <router-link :to="{ name: 'redirect_with_params', params: { id: '3' }}">Go to redirect_with_params</router-link>
</template><style scoped></style>
props传递路由组件
<script setup lang="ts">
import {ref} from "vue";const props = defineProps(['id'])
const id = ref(props.id)
</script><template><h1>TestD</h1><h1>将 props 传递给路由组件 布尔模式</h1><h1 v-text="id"></h1>
</template><style scoped></style>
<script setup lang="ts">
import {ref} from "vue";const props = defineProps(['did'])
const id = ref(props.did)
</script><template><h1>TestE</h1><h1>将 props 传递给路由组件 对象模式</h1><h1 v-text="did"></h1>
</template><style scoped></style>
<script setup lang="ts">
import {ref} from "vue";const props = defineProps(['did'])
const id = ref(props.did)
</script><template><h1>TestF</h1><h1>将 props 传递给路由组件 对象模式</h1><h1 v-text="did"></h1>
</template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router'import HomeView from "../../views/chap06/HomeView.vue";
import AboutView from "../../views/chap06/AboutView.vue";
import NotFoundView from "../../views/chap06/NotFoundView.vue";
import OrderView from "../../views/chap06/OrderView.vue";
import UserLoginView from "../../views/chap06/UserLoginView.vue";
import UserDetailView from "../../views/chap06/UserDetailView.vue";
import TestA from "../../views/chap06/TestA.vue";
import TestB from "../../views/chap06/TestB.vue";
import TestC from "../../views/chap06/TestC.vue";
import TestD from "../../views/chap06/TestD.vue";
import TestE from "../../views/chap06/TestE.vue";
import TestF from "../../views/chap06/TestF.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{path: '/', component: HomeView},{path: '/home', component: HomeView},{path: '/about', component: AboutView},// {path: '/order/:id', component: OrderView},{path: '/order/:id(\\d+)', component: OrderView},// {path: '/order/:id(.*)', component: OrderView},// {path: '/order/:id(.?)', component: OrderView},{// 嵌套路由path: '/user',children: [{path: 'login', component: UserLoginView},{path: 'detail', component: UserDetailView},]},{path: '/testA',// 命名理由name: 'nameA',// 路由别名 指的是路径的别名alias: ['/ta1', '/ta2'],component: TestA},{// 路由传参name: 'nameB',path: '/testB/:id',component: TestB},{// 路由传参name: 'nameC',path: '/testC',component: TestC},{path: '/test_redirect',// redirect: '/testA',// redirect: '/ta1',redirect: {name: 'nameA'},},{name: 'redirect_with_query',path: '/redirect_with_query',redirect: {name: 'nameC'},},{name: 'redirect_with_params',path: '/redirect_with_params/:id',redirect: to => {console.log(to)// 方法接收目标路由作为参数// return 重定向的字符串路径/路径对象// return {path: '/testC', query: {id: to.params.id}}return {name: 'nameB', params: {id: to.params.id}}},},// 将 props 传递给路由组件{name: 'nameD',path: '/testD/:id',component: TestD,// 布尔模式props: true,},{name: 'nameE',path: '/testE/:id',component: TestE,// 对象模式props: to => ({did: to.params.id}),},{name: 'nameF',path: '/testF',component: TestF,// 对象模式props: to => ({did: to.query.id}),},
]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes,
})
export default router
<script setup lang="ts">
import {useRoute} from "vue-router";const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><router-view/> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink><br/><!-- 路由传参 --><router-link :to="{ name: 'nameB', params: { id: '3' }}">Go to nameB</router-link><router-link :to="{ name: 'nameC', query: { id: '3' }}">Go to nameC</router-link> <!-- redirect 重定向 --><RouterLink :to="{path: '/test_redirect'}">Go to test_redirect</RouterLink> <router-link :to="{ name: 'redirect_with_query', query: { id: '3' }}">Go to redirect_with_query</router-link> <router-link :to="{ name: 'redirect_with_params', params: { id: '3' }}">Go to redirect_with_params</router-link><br><!-- 将 props 传递给路由组件 --><router-link :to="{ name: 'nameD', params: { id: '3' }}">Go to nameD</router-link> <router-link :to="{ name: 'nameE', params: { id: '3' }}">Go to nameE</router-link> <router-link :to="{ name: 'nameF', query: { id: '3' }}">Go to nameF</router-link>
</template><style scoped></style>
命名视图
<script setup lang="ts"></script><template>
<h1>LeftSidebar</h1>
</template><style scoped></style>
<script setup lang="ts"></script><template><h1>MainContent</h1>
</template><style scoped></style>
<script setup lang="ts"></script><template><h1>RightSidebar</h1>
</template><style scoped></style>
编程式路由
<script setup lang="ts">
import {useRoute, useRouter} from "vue-router";
// 路由对象
const router = useRouter()// 路由对象中地方路由表
const toTestA = () => {router.push('/testA')
}
const toTestAbyName = () => {router.push({name: "nameA"})
}
const toTestA1 = () => {router.push('/ta1')
}
const toTestA2 = () => {router.push('/ta2')
}const toTestB = () => {router.push({name: "nameB",params: {id: 3}})
}
const toTestC = () => {router.push({name: "nameC",query: {id: 3}})
}
const toBack = () => {router.back()
}
const route = useRoute()
</script><template><h1>忘记历史等于背叛</h1><p><strong>当前路由路径:<span v-text="route.fullPath"/></strong></p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/home">Go to Home</router-link> <router-link to="/about">Go to About</router-link> <router-link to="/order/3">Go to Order</router-link><main style="display: flex; justify-content: space-between; width: 1280px;"><!--命名视图 --><router-view name="LeftSidebar" class="content"/><router-view class="content"/><router-view name="RightSidebar" class="content"/></main> <RouterLink to="/user/login">Go to UserLogin</RouterLink> <RouterLink to="/user/detail">Go to UserDetail</RouterLink><br/><RouterLink to="/testA">Go to TestA</RouterLink> <RouterLink :to="{path: '/testA'}">Go to TestA</RouterLink> <RouterLink :to="{path: '/ta1'}">Go to TestA alias ta1</RouterLink> <RouterLink :to="{path: '/ta2'}">Go to TestA alias ta2</RouterLink><br/><!-- 路由传参 --><router-link :to="{ name: 'nameB', params: { id: '3' }}">Go to nameB</router-link><router-link :to="{ name: 'nameC', query: { id: '3' }}">Go to nameC</router-link> <!-- redirect 重定向 --><RouterLink :to="{path: '/test_redirect'}">Go to test_redirect</RouterLink> <router-link :to="{ name: 'redirect_with_query', query: { id: '3' }}">Go to redirect_with_query</router-link> <router-link :to="{ name: 'redirect_with_params', params: { id: '3' }}">Go to redirect_with_params</router-link><br><!-- 将 props 传递给路由组件 --><router-link :to="{ name: 'nameD', params: { id: '3' }}">Go to nameD</router-link> <router-link :to="{ name: 'nameE', params: { id: '3' }}">Go to nameE</router-link> <router-link :to="{ name: 'nameF', query: { id: '3' }}">Go to nameF</router-link><hr><button type="button" @click="toTestA">TestA</button><button type="button" @click="toTestAbyName">TestAbyName</button><button type="button" @click="toTestA1">TestA1</button><button type="button" @click="toTestA2">TestA2</button><button type="button" @click="toTestB">nameB</button><button type="button" @click="toTestC">nameC</button><button type="button" @click="toBack">back</button>
</template><style scoped>
.content {display: flex;justify-content: center;width: 1280px;
}
</style>
7、chap07
ajax
fetch
axios
axios
npm install axios --save
-
获取静态数据
准备
json
格式的的数据文件,保存在项目的public
目录<script setup lang="ts"> import axios from "axios";const axios_get_books = () => {axios.get("/books.json").then((response) => {console.log(response.data);}).catch((error) => {console.log(error);}); } </script><template><h1 @click="axios_get_books">AxiosLocalView</h1> </template><style scoped></style>
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router' import NotFoundView from "../../views/chap06/NotFoundView.vue"; import AxiosLocalView from "../../views/chap07/AxiosLocalView.vue"; import LoginView from "../../views/chap07/LoginView.vue"; import IndexView from "../../views/chap07/IndexView.vue"; import UserView from "../../views/chap07/UserView.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{name: 'AxiosLocalView',path: '/AxiosLocalView',component: AxiosLocalView,},{name: 'login',path: '/',component: LoginView,},{name: 'index',path: '/index',component: IndexView,},{name: 'user',path: '/user/:id(\\d+)',component: UserView,},]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createWebHistory(),routes, }) export default router
-
axios跨域
创建express项目
mkdir express cd express
npx --yes --package express-generator express --force --no-view
npm install npm start
网页访问
npm i nodemon -D
修改 package.json 文件
{"name": "express","version": "0.0.0","private": true,"scripts": {"start": "nodemon ./bin/www"},"dependencies": {"cookie-parser": "~1.4.4","debug": "~2.6.9","express": "~4.16.1","morgan": "~1.9.1"},"devDependencies": {"nodemon": "^3.1.7"} }
修改
vite.config.ts
文件实现跨域代理import {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue'const base_url = 'http://localhost:3000' // https://vitejs.dev/config/ export default defineConfig({plugins: [vue(),],server: {host: '0.0.0.0',strictPort: true,open: true,proxy: {// 使用 proxy 实例'/api': {target: 'http://localhost:3000',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, 'api'),},}}, })
编写组件
<script setup lang="ts"> import axios from "axios";const axios_get_books = () => {// axios.get("http://localhost:3000/api/books")axios.get("/api/books").then((response) => {console.log(response.data);}).catch((error) => {console.log(error)}) } </script><template><h1 @click="axios_get_books">AxiosRemoteView</h1> </template><style scoped></style>
编写路由
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router' import NotFoundView from "../../views/chap06/NotFoundView.vue"; import AxiosLocalView from "../../views/chap07/AxiosLocalView.vue"; import AxiosRemoteView from "../../views/chap07/AxiosRemoteView.vue"; import LoginView from "../../views/chap07/LoginView.vue"; import IndexView from "../../views/chap07/IndexView.vue"; import UserView from "../../views/chap07/UserView.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{name: 'AxiosLocalView',path: '/AxiosLocalView',component: AxiosLocalView,},{name: 'AxiosRemoteView',path: '/AxiosRemoteView',component: AxiosRemoteView,},{name: 'login',path: '/',component: LoginView,},{name: 'index',path: '/index',component: IndexView,},{name: 'user',path: '/user/:id(\\d+)',component: UserView,},]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
路由过度
-
安装
animate.css
动画npm install animate.css --save
-
在
main.ts
文件中引入import 'animate.css'
-
编写路由出口组件
HelloLhz
<script setup lang="ts"></script><template><!-- 想要在路由组件上使用转场 并对导航进行动画处理 --><router-view v-slot="{Component ,route}"><!--<transition name="fade" mode="out-in">--><transition mode="out-in":enter-active-class="`animate__animated ${route.meta.transitionIn}`":leave-active-class="`animate__animated ${route.meta.transitionOut}`"><component :is="Component"/></transition></router-view> </template><style scoped></style>
-
编写登录组件
<script setup lang="ts"> import {reactive} from "vue"; import {useRouter} from "vue-router";const user = reactive({account: '',password: '', }); const router = useRouter(); const onSubmit = () => {router.push({name: "index",query: user}); }; </script> <template><div class="form_container"><div class="form_item">账号:<input type="text" name="account" class="form_input" v-model="user.account"></div><div class="form_item">密码:<input type="password" name="password" class="form_input" v-model="user.password"></div><button type="button" @click="onSubmit">登录</button></div> </template><style scoped> .form_container {display: flex;flex-direction: column;justify-content: center;align-content: space-between;width: 300px; }.form_item {display: flex;flex-direction: row;justify-content: space-between;align-items: center;padding-bottom: 10px; }.form_input {width: 220px;height: 30px;padding-left: 15px; } </style>
-
编写登录后的组件
<script setup lang="ts"> </script><template><h1>忘记历史等于背叛</h1><div><!-- 想要在路由组件上使用转场 并对导航进行动画处理 --><router-view v-slot="{Component ,route}"><!--<transition name="fade" mode="out-in">--><transition mode="out-in":enter-active-class="`animate__animated ${route.meta.transitionIn}`":leave-active-class="`animate__animated ${route.meta.transitionOut}`"><component :is="Component"/></transition></router-view></div> </template><style scoped></style>
-
编写路由
import {createMemoryHistory, createWebHistory, createWebHashHistory, createRouter} from 'vue-router' import NotFoundView from "../../views/chap06/NotFoundView.vue"; import AxiosLocalView from "../../views/chap07/AxiosLocalView.vue"; import AxiosRemoteView from "../../views/chap07/AxiosRemoteView.vue"; import LoginView from "../../views/chap07/LoginView.vue"; import IndexView from "../../views/chap07/IndexView.vue"; import UserView from "../../views/chap07/UserView.vue";const routes = [// 处理404{path: '/:pathMatch(.*)*', component: NotFoundView},{name: 'AxiosLocalView',path: '/AxiosLocalView',component: AxiosLocalView,},{name: 'AxiosRemoteView',path: '/AxiosRemoteView',component: AxiosRemoteView,},{name: 'login',path: '/',component: LoginView,meta: {requiresAuth: true,transitionIn: 'animate__zoomIn',transitionOut: 'animate__zoomOut',},},{name: 'index',path: '/index',component: IndexView,meta: {requiresAuth: true,transitionIn: 'animate__zoomIn',transitionOut: 'animate__zoomOut',},},{name: 'user',path: '/user/:id(\\d+)',component: UserView,},]const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
8、chap08
piaia
-
安装pinia
npm install pinia
-
main.ts
文件中 引入pinia
import { createApp } from 'vue' import './style.css'// import router from "./router/chap06/router.ts"; // import router from "./router/chap07/router.ts"; import router from "./router/chap08/router.ts"; import App from './App.vue'import { createPinia } from 'pinia';const app = createApp(App) app.use(router)app.mount('#app')
-
编写状态文件
store.ts
import {defineStore} from 'pinia' import {computed, reactive, ref} from "vue";// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。 // (比如 `useUserStore`,`useCartStore`,`useProductStore`) // 第一个参数是你的应用中 Store 的唯一 ID。 // export const useStore = defineStore('main', { // // 为了完整类型推理,推荐使用箭头函数 // state: () => { // return { // count: 0, // users: [ // { // name: 'user0', // gender: 0 // }, // { // name: 'user1', // gender: 1 // }, // { // name: 'user2', // gender: 0 // }, // { // name: 'user3', // gender: 1 // }, // { // name: 'user4', // gender: 0 // }, // ] // } // }, // getters: { // getByGender: (state, gender) => { // return state.users.fiter(user => user.gender === gender.value); // } // }, // actions: { // findByGender: (state, gender) => { // return state.users.fiter(user => user.gender === gender.value); // } // }, // })export const useStore = defineStore('main', () => {// ref() 和 reactive() 就是 state 属性// computed() 就是 getters// function() 就是 actionsconst count = ref(0);const users = reactive([{name: 'user0',gender: 0},{name: 'user1',gender: 1},{name: 'user2',gender: 0},{name: 'user3',gender: 1},{name: 'user4',gender: 0},]);function increment() {count.value++}function updateCount(num) {count.value += num;}const gender = ref(-1)const persons = computed(() => {return gender.value === -1 ? users : users.filter(user => user.gender === gender.value)});function updateByGender(sex) {gender.value = sex}return {count, increment, updateCount, persons, updateByGender} });
-
编写视图
<script setup lang="ts"> import {useStore} from "../../store/chap08/store.ts"; import {storeToRefs} from "pinia";const store = useStore(); const {count, persons} = storeToRefs(store) const {increment, updateCount,updateByGender} = store </script><template><div><h1 v-text="count" @click="count++"></h1><h1 v-text="count" @click="increment"></h1><h1 v-text="count" @click="updateCount(5)"></h1><button type="button" @click="updateByGender(-1)">红男绿女</button><button type="button" @click="updateByGender(1)">精神小伙儿</button><button type="button" @click="updateByGender(0)">扒蒜老妹儿</button><table><thead><tr><th>姓名</th><th>性别</th></tr></thead><tbody><tr v-for="(person,index) in persons" :key="person.name"><td v-text="person.name"></td><td v-text="person.gender === 1 ? '精神小伙儿':'扒蒜老妹儿'"></td></tr></tbody></table></div> </template><style scoped> table {width: 400px; } </style>
-
编写路由
import {createRouter, createMemoryHistory} from "vue-router"; import LhzA from "../../views/chap08/LhzA.vue";const routes = [{path: "/",component: LhzA}, ] const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
9、chap09
less、sass、scss
element plus
echarts
scss
-
安装sass、scss
npm install scss --save-dev npm install scss-loader --save-dev npm install sass --save-dev npm install sass-loader --save-dev
-
编写scss文件
var.scss
-
vite.config.ts
文件中配置scssimport {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue'const base_url = 'http://localhost:3000' // https://vitejs.dev/config/ export default defineConfig({plugins: [vue(),],server: {host: '0.0.0.0',strictPort: true,open: true,proxy: {// 使用 proxy 实例'/api': {target: 'http://localhost:3000',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, 'api'),},}},css: {preprocessorOptions: {scss: {// additionalData: '@import "./src/style/var.scss";'additionalData: `@use "./src/style/var.scss" as *;`,}}} })
element plus
-
安装
element plus
npm install element-plus --save
-
引入
element plus
完整引入
按需导入
自动导入(本配置使用自动加载)
vite.config.ts
import {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'const base_url = 'http://localhost:3000' // https://vitejs.dev/config/ export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()],}),Components({// resolvers: [ElementPlusResolver({importStyle: "sass"})],resolvers: [ElementPlusResolver()],}),],server: {host: '0.0.0.0',strictPort: true,open: true,proxy: {// 使用 proxy 实例'/api': {target: 'http://localhost:3000',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, 'api'),},}},css: {preprocessorOptions: {scss: {// additionalData: '@import "./src/style/var.scss";'additionalData: `@use "./src/style/var.scss" as *;`,}}} })
echarts
-
快速入门
<!DOCTYPE html> <html><head><meta charset="utf-8" /><title>ECharts</title><!-- 引入刚刚下载的 ECharts 文件 --><script src="echarts.js"></script></head><body><!-- 为 ECharts 准备一个定义了宽高的 DOM --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: 'ECharts 入门示例'},tooltip: {},legend: {data: ['销量']},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script></body> </html>
-
安装
echarts
npm install echarts --save
-
vue
整合echarts
var.scss文件中配置单个组件高度变量
$chartHeight: 490px
CharBar.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue";const chartBar = ref() const attrs = useAttrs() const {charColor} = attrs// const chartBar = useTemplateRef('chartBar') function chartBarInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartBar.value, 'dark');// 指定图表的配置项和数据const option = reactive({color: charColor,title: {text: '柱状图'},tooltip: {},legend: {data: ['销量']},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartBarInit() }) </script><template><div id="chartBar" ref="chartBar"></div> </template><style scoped lang="scss"> #chartBar {width: 100%;height: $chartHeight; } </style>
-
首页布局
IndexView.vue
<script setup lang="ts"> import ChartBar from "./chartBar/ChartBar.vue"; import ChartLine from "./chartLine/ChartLine.vue"; import ChartMap from "./chartMap/ChartMap.vue"; import ChartPie from "./chartPie/ChartPie.vue"; import ChartRadar from "./chartRadar/ChartRadar.vue"; </script><template><div><div class="index-container"><div class="side-item"><div class="item"><chart-bar :charColor="'#1e9fff'"/></div><div class="item"><chart-pie/></div></div><div class="side-item" style="flex: 0 1 150%"><div class="item"><chart-map/></div></div><div class="side-item"><div class="item"><chart-radar/></div><div class="item"><chart-line :charColor="'#1e9fff'"/></div></div></div></div> </template><style scoped> .index-container {width: 100%;display: flex;flex-direction: row;justify-content: space-between;align-items: stretch;.side-item {width: 100%;display: flex;flex-direction: column;justify-content: space-between;align-content: stretch;}.item {padding: 10px;} } </style>
-
柱状图
ChartBar.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue";const chartBar = ref() const attrs = useAttrs() const {charColor} = attrs// const chartBar = useTemplateRef('chartBar') function chartBarInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartBar.value, 'dark');// 指定图表的配置项和数据const option = reactive({color: charColor,title: {text: '柱状图'},tooltip: {},legend: {data: ['销量']},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartBarInit() }) </script><template><div id="chartBar" ref="chartBar"></div> </template><style scoped lang="scss"> #chartBar {width: 100%;height: $chartHeight; } </style>
ChartBarView.vue
<script setup lang="ts"> import ChartBar from "./ChartBar.vue"; </script><template><div><div class="index-container"><div style="flex: 0 1 30%"><div class="item"><chart-bar :charColor="'#dd6b66'"/></div></div><div style="flex: 0 1 70%"><div class="item"><chart-bar :charColor="'#1e9fff'"/></div></div></div><div class="index-container"><div style="flex: 0 1 70%"><div class="item"><chart-bar :charColor="'#16b777'"/></div></div><div style="flex: 0 1 30%"><div class="item"><chart-bar :charColor="'#a233c6'"/></div></div></div></div> </template><style scoped> .index-container {width: 100%;display: flex;flex-direction: row;.item{padding: 10px;} } </style>
-
折线图
ChartLine.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue";const chartLine = ref() const attrs = useAttrs() const {charColor} = attrs// const chartBar = useTemplateRef('chartBar') function chartBarInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartLine.value, 'dark');// 指定图表的配置项和数据const option = reactive({color: charColor,title: {text: '折线图'},tooltip: {},legend: {data: ['pay']},xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},yAxis: {type: 'value'},series: [{name: 'pay',data: [820, 932, 901, 934, 1290, 1330, 1320],type: 'line',smooth: true}]});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartBarInit() }) </script><template><div id="chartLine" ref="chartLine"></div> </template><style scoped lang="scss"> #chartLine {width: 100%;height: $chartHeight; } </style>
ChartLineView.vue
<script setup lang="ts"> import ChartLine from "./ChartLine.vue"; </script><template><div><div class="index-container"><div style="flex: 0 1 30%"><div class="item"><chart-line :charColor="'#dd6b66'"/></div></div><div style="flex: 0 1 70%"><div class="item"><chart-line :charColor="'#1e9fff'"/></div></div></div><div class="index-container"><div style="flex: 0 1 70%"><div class="item"><chart-line :charColor="'#16b777'"/></div></div><div style="flex: 0 1 30%"><div class="item"><chart-line :charColor="'#a233c6'"/></div></div></div></div> </template><style scoped> .index-container {width: 100%;display: flex;flex-direction: row;.item{padding: 10px;} } </style>
-
饼图
ChartPie.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue";const chartPie = ref() const attrs = useAttrs()// const chartPie = useTemplateRef('chartPie') function chartPieInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartPie.value, 'dark');// 指定图表的配置项和数据const option = reactive({title: {text: 'Referer of a Website',subtext: 'Fake Data',left: 'center'},tooltip: {trigger: 'item'},legend: {orient: 'vertical',left: 'left'},series: [{name: 'Access From',type: 'pie',radius: '50%',data: [{value: 1048, name: 'Search Engine'},{value: 735, name: 'Direct'},{value: 580, name: 'Email'},{value: 484, name: 'Union Ads'},{value: 300, name: 'Video Ads'}],emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartPieInit() }) </script><template><div id="chartPie" ref="chartPie"></div> </template><style scoped lang="scss"> #chartPie {width: 100%;height: $chartHeight; } </style>
ChartPieView.vue
<script setup lang="ts"> import ChartPie from "./ChartPie.vue"; </script><template><div><div class="index-container"><div style="flex: 0 1 30%"><div class="item"><chart-pie/></div></div><div style="flex: 0 1 70%"><div class="item"><chart-pie/></div></div></div><div class="index-container"><div style="flex: 0 1 70%"><div class="item"><chart-pie/></div></div><div style="flex: 0 1 30%"><div class="item"><chart-pie/></div></div></div></div> </template><style scoped> .index-container {width: 100%;display: flex;flex-direction: row;.item{padding: 10px;} } </style>
-
雷达图
ChartRadar.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue";const chartRadar = ref() const attrs = useAttrs()// const chartRadar = useTemplateRef('chartRadar') function chartRadarInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartRadar.value, 'dark');// 指定图表的配置项和数据const option = reactive({title: {text: 'Basic Radar Chart'},legend: {data: ['Allocated Budget', 'Actual Spending']},radar: {// shape: 'circle',indicator: [{name: 'Sales', max: 6500},{name: 'Administration', max: 16000},{name: 'Information Technology', max: 30000},{name: 'Customer Support', max: 38000},{name: 'Development', max: 52000},{name: 'Marketing', max: 25000}]},series: [{name: 'Budget vs spending',type: 'radar',data: [{value: [4200, 3000, 20000, 35000, 50000, 18000],name: 'Allocated Budget'},{value: [5000, 14000, 28000, 26000, 42000, 21000],name: 'Actual Spending'}]}]});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartRadarInit() }) </script><template><div id="chartRadar" ref="chartRadar"></div> </template><style scoped lang="scss"> #chartRadar {width: 100%;height: $chartHeight; } </style>
ChartRadarView.vue
<script setup lang="ts"> import ChartRadar from "./ChartRadar.vue"; </script><template><div><div class="index-container"><div style="flex: 0 1 30%"><div class="item"><chart-radar/></div></div><div style="flex: 0 1 70%"><div class="item"><chart-radar/></div></div></div><div class="index-container"><div style="flex: 0 1 70%"><div class="item"><chart-radar/></div></div><div style="flex: 0 1 30%"><div class="item"><chart-radar/></div></div></div></div> </template><style scoped> .index-container {width: 100%;display: flex;flex-direction: row;.item{padding: 10px;} } </style>
-
地图
提前准备
省份json
文件和经纬度坐标
文件ChartMap.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue"; import china_province from "../../../store/chap09/china_province.json" import china_geo from "../../../store/chap09/china_full.json"const chartMap = ref() const attrs = useAttrs() const convertData = function (data) {let res = [];for (let i = 0; i < data.length; i++) {let geoCoord = china_geo.features[i].properties;if (geoCoord) {res.push({name: data[i].name,value: geoCoord.center.concat(data[i].value)});}}return res; };// const chartMap = useTemplateRef('chartMap') function chartMapInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartMap.value, 'dark');// 注入地图数据 GeoJson 注意第一个参数为 china 才会显示 海南岛缩略图 其它名字不会echarts.registerMap('china', china_geo);// 指定图表的配置项和数据const option = reactive({title: {text: '全国主要城市空气质量 - 百度地图',left: 'center'},tooltip: {trigger: 'item',formatter: function (params) {// console.log(params);return `${params.data.name}:${params.data.value[2]}`}},// 地图配置geo: {type: 'map',// chinaMap 这个参数 为 echarts.registerMap('chinaMap', response); 参数中第一个参数// 注意参数为 china 才会显示 海南岛缩略图 其它名字不会map: 'china',// 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启roam: true,// 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等label: {// 是否显示标签show: true},// 默认缩放比例zoom: 1.1,// 地图中心点坐标// 当前视角的中心点,默认使用原始坐标(经纬度)。如果设置了projection则用投影后的坐标表示。// center: [125.3245, 43.886841]},series: [{geoIndex: 0,type: 'effectScatter',// 配置何时显示特效// 'render' 绘制完成后显示特效// 'emphasis' 高亮(hover)的时候显示特效。showEffectOn: 'render',// data: [{ name: '北京市', value: [116.405285, 39.904989, 9] }],data: convertData(china_province),// 使用地理坐标系,通过 geoIndex 指定相应的地理坐标系组件。coordinateSystem: 'geo',symbolSize: function (param) {// console.log(param[2]);return param[2] / 2},},],// 是视觉映射组件,用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道visualMap: {min: 0,max: 50,// 筛选calculable: true}});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartMapInit() }) </script><template><div id="chartMap" ref="chartMap"></div> </template><style scoped lang="scss"> #chartMap {width: 100%;height: 1000px; } </style>
-
编写路由
import {createRouter, createMemoryHistory} from "vue-router"; import IndexView from "../../views/chap09/IndexView.vue"; import ChartBarView from "../../views/chap09/chartBar/ChartBarView.vue"; import ChartLineView from "../../views/chap09/chartLine/ChartLineView.vue"; import CharPieView from "../../views/chap09/chartPie/ChartPieView.vue"; import ChartRadarView from "../../views/chap09/chartRadar/ChartRadarView.vue"; import ChartMap from "../../views/chap09/chartMap/ChartMap.vue";const routes = [{path: "/",name: "index",component: IndexView},{path: "/ChartBarView",name: "ChartBarView",component: ChartBarView},{path: "/ChartLineView",name: "ChartLineView",component: ChartLineView},{path: "/CharPieView",name: "CharPieView",component: CharPieView},{path: "/ChartRadarView",name: "ChartRadarView",component: ChartRadarView},{path: "/ChartMap",name: "ChartMap",component: ChartMap}, ] const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
width: 100%;
display: flex;
flex-direction: row;
.item{
padding: 10px;
}
}
```
-
地图
提前准备
省份json
文件和经纬度坐标
文件ChartMap.vue
<script setup> import * as echarts from 'echarts'; // import { BarChart } from 'echarts/charts'; import {ref, reactive, onMounted, useAttrs, useTemplateRef} from "vue"; import china_province from "../../../store/chap09/china_province.json" import china_geo from "../../../store/chap09/china_full.json"const chartMap = ref() const attrs = useAttrs() const convertData = function (data) {let res = [];for (let i = 0; i < data.length; i++) {let geoCoord = china_geo.features[i].properties;if (geoCoord) {res.push({name: data[i].name,value: geoCoord.center.concat(data[i].value)});}}return res; };// const chartMap = useTemplateRef('chartMap') function chartMapInit() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(chartMap.value, 'dark');// 注入地图数据 GeoJson 注意第一个参数为 china 才会显示 海南岛缩略图 其它名字不会echarts.registerMap('china', china_geo);// 指定图表的配置项和数据const option = reactive({title: {text: '全国主要城市空气质量 - 百度地图',left: 'center'},tooltip: {trigger: 'item',formatter: function (params) {// console.log(params);return `${params.data.name}:${params.data.value[2]}`}},// 地图配置geo: {type: 'map',// chinaMap 这个参数 为 echarts.registerMap('chinaMap', response); 参数中第一个参数// 注意参数为 china 才会显示 海南岛缩略图 其它名字不会map: 'china',// 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启roam: true,// 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等label: {// 是否显示标签show: true},// 默认缩放比例zoom: 1.1,// 地图中心点坐标// 当前视角的中心点,默认使用原始坐标(经纬度)。如果设置了projection则用投影后的坐标表示。// center: [125.3245, 43.886841]},series: [{geoIndex: 0,type: 'effectScatter',// 配置何时显示特效// 'render' 绘制完成后显示特效// 'emphasis' 高亮(hover)的时候显示特效。showEffectOn: 'render',// data: [{ name: '北京市', value: [116.405285, 39.904989, 9] }],data: convertData(china_province),// 使用地理坐标系,通过 geoIndex 指定相应的地理坐标系组件。coordinateSystem: 'geo',symbolSize: function (param) {// console.log(param[2]);return param[2] / 2},},],// 是视觉映射组件,用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道visualMap: {min: 0,max: 50,// 筛选calculable: true}});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);window.addEventListener('resize', function () {myChart.resize();}); }onMounted(() => {chartMapInit() }) </script><template><div id="chartMap" ref="chartMap"></div> </template><style scoped lang="scss"> #chartMap {width: 100%;height: 1000px; } </style>
-
编写路由
import {createRouter, createMemoryHistory} from "vue-router"; import IndexView from "../../views/chap09/IndexView.vue"; import ChartBarView from "../../views/chap09/chartBar/ChartBarView.vue"; import ChartLineView from "../../views/chap09/chartLine/ChartLineView.vue"; import CharPieView from "../../views/chap09/chartPie/ChartPieView.vue"; import ChartRadarView from "../../views/chap09/chartRadar/ChartRadarView.vue"; import ChartMap from "../../views/chap09/chartMap/ChartMap.vue";const routes = [{path: "/",name: "index",component: IndexView},{path: "/ChartBarView",name: "ChartBarView",component: ChartBarView},{path: "/ChartLineView",name: "ChartLineView",component: ChartLineView},{path: "/CharPieView",name: "CharPieView",component: CharPieView},{path: "/ChartRadarView",name: "ChartRadarView",component: ChartRadarView},{path: "/ChartMap",name: "ChartMap",component: ChartMap}, ] const router = createRouter({// 4. 内部提供了 history 模式的实现。// memory 模式。createMemoryHistory// hash 模式。createWebHashHistory// html5 模式。createWebHistoryhistory: createMemoryHistory(),routes, }) export default router
相关文章:
vue + echarts 快速入门
vue echarts 快速入门 本案例即有nodejs和vue的基础,又在vue的基础上整合了echarts Nodejs基础 1、Node简介 1.1、为什么学习Nodejs(了解) 轻量级、高性能、可伸缩web服务器前后端JavaScript同构开发简洁高效的前端工程化 1.2、Nodejs能做什么(了解) Node 打破了…...
服务器几核几G几M是什么意思?如何选择?
服务器几核几G几M是什么意思?我们建站、搭建网络平台都要用到云服务器,不管在腾讯云、阿里云还是别的云服务平台选购,都会接触到服务器配置。云服务器就是把物理服务器(俗称“母鸡”),用虚拟机技术虚拟出多…...
K8S服务发布
一 、服务发布方式对比 二者主要区别在于: 1、部署复杂性:传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等,过程相对复 杂且容易出错。相比之下,Kubernetes服务发布方式 通过使用容器编排和自动化部署工…...
Allen Institute for Artificial Intelligence (Ai2) 发布开源多模态语言模型 Molmo
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
Html CSS 布局,位置处理 居中 对齐
Html CSS 布局,位置处理 1、居中布局 1、div 让内部div居中对齐 html <div class"container"><div class"item">I am centered!</div> </div>style .container {border: 2px solid rgb(75, 70, 74);border-radius:…...
Spring MVC系统学习(二)——Spring MVC的核心类和注解
Spring MVC(Model-View-Controller)是Spring框架的一个模块,用于构建基于Web的应用程序。它使用模型、视图和控制器分离的设计模式,使得Web开发更加模块化和灵活。在学习Spring MVC时,有几个核心类和注解是非常关键的&…...
conda虚拟环境安装包、依赖同一管理
在 Python 的虚拟环境中,每个环境都是独立的,这意味着即使两个环境需要相同的库,它们也会分别安装各自的副本。这样做是为了避免不同项目之间相互影响,确保每个项目都有一个干净且隔离的环境。 方法一:使用 Conda 的共…...
Unity网络开发记录(四):在unity中进一步封装客户端类
在上一篇文章中,简单的封装了一下服务端中相关的socket对象,为了可以更方便的使用。所以在本篇中,进一步封装一下在unity中的相关客户端类 封装客户端类,首先采用单例模式,然后采用两个队列来存储我们相关的收发信息 p…...
Linux内核中的UART驱动-详解Linux内核UART驱动:结构与功能分析
一、UART概述 UART(Universal Asynchronous Receiver/Transmitter),即通用异步收发器,是一种串行通信接口,用于在计算机和外部设备之间传输数据。它特别适用于短距离、低速、串行和全双工的数据传输。在Linux内核中&a…...
威胁检测与防范:如何及时、准确对抗安全风险
随着技术的飞速发展,网络空间中的威胁日益多样化、隐蔽化,给个人、企业乃至国家的信息安全带来诸多挑战。面对严峻的网络威胁,传统的防火墙、入侵检测系统(IDS)等防御手段虽能在一定程度上抵御外部攻击,但依…...
数据结构串的kmp相关(求next和nextval)
傻瓜版,用来演示手算过程,个人理解用的,仅供参考。...
创建游戏暂停菜单
创建用户控件 设置样式 , 加一层 背景模糊 提升UI菜单界面质感 , 按钮用 灰色调 编写菜单逻辑 转到第三人称蓝图 推荐用 Set Input Mode Game And UI , 只用仅UI的话 增强输入响应不了 让游戏暂停的话也可以用 Set Game Paused , 打勾就是暂停 , 不打勾就是继续游戏 , 然后…...
seata服务端部署
1.下载seata 官网下载地址:http://seata.io/zh-cn/blog/download.html 或者下载 作者已经下载的压缩包1.4.0 注意!!! 要参考对应的版本,否则可能出现无法正常启动的情况。 参考文档 下载完毕后解压压缩文件 2.修改配…...
理解Python闭包概念
闭包并不只是一个python中的概念,在函数式编程语言中应用较为广泛。理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想。 1.概念介绍 首先看一下维基上对闭包的解释: 在计算机科学中,闭包…...
51单片机的教室智能照明系统【proteus仿真+程序+报告+原理图+演示视频】
1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块DS1302时钟模块光照传感器红外传感器温度传感器LED等模块构成。适用于教室灯光全自动控制、教室节能灯控制、教室智能照明等相似项目。 可实现功能: 1、LCD1602实时显示时间、温度、光照强度等信息 2、光照强度传…...
一款资产进行快速存活验证工具
01工具介绍 (下载地址见最后) 在日常工作的渗透测试过程中,经常会碰到渗透测试项目,而Web渗透测试通常是渗透项目的重点或者切入口。通常拿到正规项目授权后,会给你一个IP资产列表和对应的Web资产地址,这时…...
I/O中断处理过程
中断优先级包括响应优先级和处理优先级,响应优先级由硬件线路或查询程序的查询顺序决定,不可动态改变。处理优先级可利用中断屏蔽技术动态调整,以实现多重中断。下面来看他们如何运用在中断处理过程中: 中断控制器位于CPU和外设之…...
关于PHP 匿名函数在处理数据结构中的应用
PHP 的匿名函数(也称为闭包)在处理数据结构时非常有用。它们可以在需要一次性函数的情况下使用,例如数组函数的回调、事件处理或作为其他函数的参数。以下是一些常见的应用场景: 数组操作: 使用 array_map、array_fil…...
安卓13默认使用大鼠标 与配置分析 andriod13默认使用大鼠标 与配置分析
总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android13里面的鼠标貌似比以前版本的鼠标小了,有些客户想要把这个鼠标改大。这个功能,android有现成的,就在这里,设置 =》无障碍 =》色彩和动画 =》 大号鼠标指针。 我们通过…...
AI学习指南深度学习篇-批标准化在深度学习中的应用
AI学习指南深度学习篇-批标准化在深度学习中的应用 引言 批标准化(Batch Normalization, BN)是一种在深度学习中常用的技术,旨在加速训练过程并提高模型的稳定性。它通过标准化每一个小批量的激活值,减小内部协变量偏移…...
了解网络的相关信息
文章目录 前言了解网络的相关信息1. ip是什么?1.1. 公网IP:1.2. 私有IP:1.2.1. 示例 2. 子网掩码3. 子网掩码的划分网段是什么4. 特殊的回路IP网段(127.0.0.1)5. 端口 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊&#x…...
Java | Leetcode Java题解之第447题回旋镖的数量
题目: 题解: class Solution {public int numberOfBoomerangs(int[][] points) {int ans 0;for (int[] p : points) {Map<Integer, Integer> cnt new HashMap<Integer, Integer>();for (int[] q : points) {int dis (p[0] - q[0]) * (p[…...
Docker实践与应用举例
引言 Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。本文将详细介绍 Dock…...
828华为云征文 | 智能监控新篇章,Prometheus如何在华为云Flexusx容器环境中大展身手
前言 在数字化转型的浪潮中,智能监控成为企业IT战略的关键环节。部署在华为云Flexus X实例上的Prometheus监控系统,凭借其卓越的性能与灵活性,正开启智能监控的新篇章。Flexus X实例以其强大的计算能力和灵活的资源管理,为Prometh…...
基于单片机的可调式中文电子日历系统
** 文章目录 前言概要功能设计软件设计效果图 程序文章目录 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们…...
《C++设计新思维-泛型编程与设计模式之应用》阅读记录
目录 写在前面policy和policy class的认识 写在前面 这本书是2003年出版的,大佬侯捷翻译的,21年前的书了,最近打算翻一翻。 看这种技术书籍,特别是简历理论体系的书籍,最好看纸质书。 本书从根本上展示了generic pa…...
vue访问组件的数据和方法
组件源码 <template><view class"c_container" :style"myStyle" click"clickCust"><view style"font-size: 18px;text-align: center;">{{item.name}}</view><view style"margin-top: 10px;font-siz…...
Redis: RDB与AOF的选择和容灾备份以及Redis数据持久化的优化方案
如何选择RDB和AOF 1 )同时开启 在我们 Redis 的服务器上,把RDB和AOF同时打开, 这样可以通过RDB快速的恢复数据,因为它是一个紧凑的缩缩的二进制文件, 但是有时 Redis 的不小心故障了,丢失了十几分钟的数据 可以通过AOF来做数据的…...
Goweb---Gorm操作数据库(二)
Gorm允许用户自己自定义钩子操作,使用这些钩子操作,可以在增删改查操作前进行相关的操作和检验,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。 自定义钩子函数 package ma…...
鸿蒙HarmonyOS之封装Http请求工具类
一、常量类 Constants.ets //超时时间10秒 static readonly HTTP_READ_TIMEOUT: number 10000;//请求成功返回码 static readonly HTTP_CODE_200: number 200;//请求成功后data中的code值(根据实际情况定) static readonly SERVER_CODE_SUCCESS: numb…...
最好的营销型网站建设公司/南宁网站seo优化公司
初学JDBC,看了看书,自己动手的时候还是有很多地方有问题,最终终于解决了实现了数据库的连接。现将整个步骤描述如下:环境:mySQL5.1.26(win 32bit), Eclipse JavaEE IDE1mySQL的安装:最新版本是5.1.26&#…...
建设工程安全监督备案网站/如何弄一个自己的网站
本文由Jamie Shields和Wern Ancheta进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态! SoundCloud提供了一个API,使开发人员可以获取他们想要的几乎所有数据。 但是它的用法可能会引起混淆,尤其是对于初学者而言…...
廊坊模板网站建设/百度竞价推广出价技巧
本系统为牛旦教育IT课堂在微头条上发布的内容,为便于查阅,特辑录于此,都是常用SQL基本用法。前两篇连接:(一):SQL点滴(查询篇):数据库基础查询案例实战(二):SQL点滴(排序篇):数据常规…...
建站行业现状探讨/优化网站有哪些方法
隐式意图在很多app中应用广泛,使用隐式意图不仅可以启动自己程序中的Activity,还可以启动其他程序中的Activity,使得程序之间可以共享某种功能。以下将对于用过的setAction()的方法作以归纳整理,持续更新… 1、android.intent.ac…...
wordpress 邮箱留言/品牌网
紫上给得比较奇怪,其实没有必要用唯一分解定理。我觉得这道题用唯一分解只是为了表示大数。 但是分解得到的幂,累乘的时候如果顺序很奇怪也可能溢出。其实直接边乘边除就好了。因为答案保证不会溢出, 设定一个精度范围,如果中间结…...
wordpress科技企业主题/semantic ui
一:连接池的定义本质上就是个容器(集合) 存放数据库连接的容器,当系统初始化后,容器被创建,容器中就会申请一些连接对象,当用户来访问数据库的时候,从容器中取连接对象,用户用完之后,…...