Node.js
Node.js 是一个基于 Chrome V8 引擎的 Javascript 运行环境
NPM (Node Package Manager)
软件包仓库
在 src/vue.config.js 文件中加入
module.exports = { // 避免Eslint报错 lintOnSave: false }
tsconfig.json 配置文件
{ "compilerOptions": { /* 访问 https://aka.ms/tsconfig.json 以阅读有关此文件的更多信息 */ /* 基本选项 */ "incremental": true, /* 启用增量编译 */ "target": "ESNEXT", /* 指定 ECMAScript 目标版本:'ES3'、'ES5'(默认)、'ES2015'、'ES2016'、'ES2017'、'ES2018'、'ES2019'、'ES2020' 或 'ESNEXT'。 */ "module": "commonjs", /* 指定模块代码生成:“none”、“commonjs”、“amd”、“system”、“umd”、“es2015”、“es2020”或“ESNext”。 */ "lib": [], /* 指定要包含在编译中的库文件。 */ "allowJs": true, /* 允许编译 javascript 文件。 */ "checkJs": true, /* 报告 .js 文件中的错误。 */ "jsx": "preserve", /* 指定 JSX 代码生成:'preserve'、'react-native' 或 'react'。 */ "declaration": true, /* 生成相应的“.d.ts”文件。 */ "declarationMap": true, /* 为每个对应的“.d.ts”文件生成一个源映射。 */ "sourceMap": true, /* 生成相应的“.map”文件。 */ "outFile": "./", /* 连接输出到单个文件。 */ "outDir": "./", /* 将输出结构重定向到目录。 */ "rootDir": "./", /* 指定输入文件的根目录。用于通过 --outDir 控制输出目录结构。 */ "composite": true, /* 启用项目编译 */ "tsBuildInfoFile": "./", /* 指定文件存放增量编译信息 */ "removeComments": true, /* 不要向输出发出注释(删除除代码注释)。 */ "noEmit": true, /* 不发出输出(不生成编译后的文件)。 */ "noEmitOnError": true, /* 在输出js代码时,如果有错将不编译文件。 */ "importHelpers": true, /* 从 'tslib' 导入发射助手。 */ "downlevelIteration": true, /* 以“ES5”或“ES3”为目标时,为“for-of”、展开和解构中的迭代提供全面支持。 */ "isolatedModules": true, /* 将每个文件转换为一个单独的模块(类似于 'ts.transpileModule')。 */ /* 严格的类型检查选项 */ "strict": true, /* 启用所有严格的类型检查选项。 在开发中,建议将stricet这类选项都开启。 */ "strictNullChecks": true, /* 启用严格的空(undefined、null)检查,可以防止“未定义不是对象”。 建议开启*/ "strictFunctionTypes": true, /* 启用函数类型的严格检查。 */ "strictBindCallApply": true, /* 在函数上启用严格的“绑定”、“调用”、应用”方法。 */ "strictPropertyInitialization": true, /* 启用对类中属性初始化的严格检查。 */ "noImplicitThis": true, /* 使用隐含的“any”类型在“this”表达式上引发错误。 */ "noImplicitAny": true, /* 使用隐含的“any”类型在表达式和声明上引发错误(主要用于控制变量、参数是否必须知道它们的类型【类型检查】),如果是将JavaScript迁移到TypeScript时,可以关闭此项,但不建议这样做。 */ "alwaysStrict": true, /* 以严格模式解析并为每个源文件发出“使用严格”。 */ /* 额外检查 */ "noUnusedLocals": true, /* 报告未使用的本地人的错误。 */ "noUnusedParameters": true, /* 报告未使用参数的错误。 */ "noImplicitReturns": true, /* 不是函数中的所有代码路径都返回值时报告错误。 */ "noFallthroughCasesInSwitch": true, /* 在 switch 语句中报告失败情况的错误。 */ /* 模块分辨率选项 */ "moduleResolution": "node", /* 指定模块解析策略:'node' (Node.js) 或 'classic' (TypeScript pre-1.6)。 */ "baseUrl": "./", /* 解析非绝对模块名称的基目录。 */ "paths": {}, /* 一系列将导入重新映射到相对于“baseUrl”的查找位置的条目。 */ "rootDirs": [], /* 根文件夹列表,其组合内容代表运行时项目的结构。 */ "typeRoots": [], /* 包含类型定义的文件夹列表。 */ "types": [], /* 类型声明文件要包含在编译中。 */ "allowSyntheticDefaultImports": true, /* 允许从没有默认导出的模块中默认导入。 这不会影响代码发出,只是类型检查。 */ "esModuleInterop": true, /* 通过为所有导入创建命名空间对象,在 CommonJS 和 ES 模块之间启用发射互操作性。 暗示“allowSyntheticDefaultImports”。 */ "preserveSymlinks": true, /* 不解析符号链接的真实路径。 */ "allowUmdGlobalAccess": true, /* 允许从模块访问 UMD 全局变量。 */ /* 源映射选项 */ "sourceRoot": "", /* 指定调试器应该定位 TypeScript 文件而不是源位置的位置。 */ "mapRoot": "", /* 指定调试器应该定位映射文件而不是生成位置的位置。 */ "inlineSourceMap": true, /* 发出带有源映射的单个文件而不是单独的文件。 */ "inlineSources": true, /* 在单个文件中与源映射一起发出源; 需要设置“--inlineSourceMap”或“--sourceMap”。 */ /* 实验选项 */ "experimentalDecorators": true, /* 启用对 ES7 装饰器的实验性支持。 */ "emitDecoratorMetadata": true, /* 为装饰器的发射类型元数据启用实验性支持。 */ /* 高级选项 */ "skipLibCheck": true, /* 跳过声明文件的类型检查。 */ "forceConsistentCasingInFileNames": true /* 禁止对同一文件的大小写不一致的引用。 */ } }
在 src 下创建文件 vite-env.d.ts
///
interface ImportMetaEnv { readonly VITE_BASE_URL: string; readonly VITE_BASE_WS: string; // 更多环境变量... } interface ImportMeta { readonly env: ImportMetaEnv; } declare module "*.vue" { import type { DefineComponent } from "vue"; const component: DefineComponent<{}, {}, any>; export default component; } // 原生交互参数定义 interface Window { $message: any } declare module 'qrcodejs2-fix';
‘./’ – 当前所在目录,可不写
‘…/’ – 上一级目录
‘/’ – 根目录
jpg | .jpg/.jpeg 有损压缩 占用空间小 |
---|---|
png | .png 无损压缩 占用空间略大 |
bmp | .bmp 不压缩 占用空间极大 |
gif | .gif 动态图 |
api 与后端交互的接口,协议
assets
icon 图标
images 图片
style 样式components 公共组件
layouts 项目整体布局
loacles 多语言
router 路由
store 前端数据缓存 (项目中用 pinia)
types 定义数据结构
utils 工具类
view 视图
类似于继承,所有对象上都有 [[Prototype]] 属性,代表父类中的方法
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法
Date
对象从Date.prototype
继承。Array
对象从Array.prototype
继承。Person
对象从Person.prototype
继承。
var TestPrototype = function () {
this.propA = 1;
this.methodA = function() {
return this.propA;
}
}
TestPrototype.prototype = {
methodB: function() {
return this.propA;
}
}
var objA = new TestPrototype();
var objB = new TestPrototype();
objA.methodA() // 1
objA.methodB() // 1
objA === objB // false
objA.methodA === objB.methodA // false
objA.methodB === objB.methodB // true
导出
①默认导出:export default Test(导入时可指定模块任意名称,无需知晓内部真实名称)
②单独导出:export const name = "Bruce"
③按需导出:export { age, name, sex }(推荐)
④改名导出:export { name as newName }
导入
①默认导入:import Test from "test"
②整体导入:import * as Test from "test"
③按需导入:import { age, name, sex } from "test"
④改名导入:import { name as newName } from "test"
//trim()例子
let str = ' hello '
console.log(str.trim()) //hello
!
非空断言操作符
用于断言操作对象是非 null 和非 undefined 类型type HandleChange= () => void; function myFunc(onChange: HandleChange | undefined) { //如果不加!,会报错 const a = onChange(); // Error const b = onChange!(); //OK }
?.
遇到 null 或 undefined 就可以立即停止表达式的运行
??
当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数
console.log(false ?? '哈哈哈') // false console.log(null ?? '哈哈哈') // 哈哈哈
let deepObj = JSON.parse(JSON.stringify(obj));
let arr = [1, 2]
let arr2 = [3, 4]
arr = [...arr, ...arr2]
console.log(arr)
// [1, 2, 3, 4]
JSON.parse() 将字符串转换为 JavaScript 对象。
// JSON.parse(text[, reviver])
// text: 一个有效的 JSON 字符串, reviver: 一个转换结果的函数, 将为对象的每个成员调用此函数。
let obj = JSON.parse('{ "name":"runoob", "alexa":10000, "site":"www.runoob.com" }', (key, value) => {
if(key) {
console.log(`读取到${key}属性,值为:${value}`)
}
});
// 读取到name属性,值为:runoob
// Game.vue:13 读取到alexa属性,值为:10000
// Game.vue:13 读取到site属性,值为:www.runoob.com
JSON.stringify() 将 JavaScript 对象转换为字符串。
// JSON.stringify(value[, replacer[, space]])
// value: 要转换的 JavaScript 值(通常为对象或数组) replacer 传入每个成员的键和值。使用返回值
let obj = {
"name":"runoob",
"alexa":10000,
"site":"www.runoob.com"
}
let myJson = JSON.stringify(obj)
console.log(myJson)
// {"name":"runoob","alexa":10000,"site":"www.runoob.com"}
scrollTop, scrollHeight, clientHeight
- scrollTop:元素顶部到元素可视区域顶部的像素距离(可读写)。
- scrollHeight:类似于clientHeight,但包括由于overflow属性不可见内容的高度。
- clientHeight:元素的像素高度,包括盒子内容content和内边距padding, 不包括边框外边距和水平滚动条(只读)
滚动到底部判断:element.scrollHeight-element.scrollTop=element.clientHeight
DOCTYPE HTML>
<HTML lang="en">
<head>
<meta charset="UTF-8">
<title>my HTMLtitle>
head>
<body>
我的第一个HTML网页
body>
HTML>
块级元素:独占一行,块级元素内能写任何元素
行内元素:不独占一行,行内元素内能写行内元素,但不能写块级元素
<div> div>
常用:
em | 用户着重阅读的内容 |
---|---|
strong | 表示文本十分重要,一般用粗体显示 |
span | 元素是短语内容的通用行内容器,并没有任何特殊语义。 |
不常用:
cite | 表示一个作品的引用,且必须包含作品的标题 |
---|---|
dfn | 特殊术语,或专属名词 |
del 与 ins | 删除的文字内容【与】插入文档中的文本 |
sub 与 sup | 下标文字【与】上标文字 |
code | 一段代码 |
samp | 标识计算机程序输出 |
kbd | 键盘输入元素,用于表示用户输入 |
addr | 联系信息,说明,配合 title 属性使用 |
bdo | 改写了文本的方向性,配合 dir 属性使用 |
var | 变量 |
address | 某个人或某个组织(等等)的联系信息。 |
标签名 | 属性 | 说明 |
---|---|---|
img | src(相对路径),alt(图像描述,利于搜索) | 单标签 |
标签名 | 属性 | 说明 |
---|---|---|
img | href(跳转网址),target(新页面从哪打开) download=“name”(将链接的 URL 视为下载资源) | 单标签,超链接 |
通过超链接跳转锚点:
<body>
<a href="#5">测试超链接跳转锚点a>
<p>我是锚点1p>
<p>我是锚点2p>
<p>我是锚点3p>
<p>我是锚点4p>
<p id="5">我是锚点5p>
body>
<a href="#">回到顶部a>
超链接唤起指定应用:
<a href="tel:10086">电话联系a>
<a href="mailto:[email protected]">邮件联系a>
<a href="sms:10086">短信联系a>
4.1 ol (有序列表)
<h2>把大象装进冰箱分几步h2>
<ol>
<li>打开冰箱门li>
<li>大象放进去li>
<li>关上冰箱门li>
ol>
4.2 ul (无序列表)
<h2>我想去的几个城市h2>
<ul>
<li>云南li>
<li>成都li>
<li>重庆li>
ul>
dl (自定义列表)
<h2>我想去的几个城市h2>
<dl>
<dt>做好笔记dt>
<dd>好记性不如烂笔头dd>
<dt>多加练习dt>
<dd>实践出真知dd>
<dt>别怕失败dt>
<dd>失败是成功之母dd>
dl>
注意点
列表可嵌套使用
<ul>
<li>云南li>
<li>成都li>
<li>
<span>上海span>
<ul>
<li>外滩li>
<li>东方明珠li>
<li>迪士尼乐园li>
ul>
li>
ul>
自定义列表一个术语可有多个描述
- 做好笔记
- 好记性不如烂笔头
- 笔记可以是电子版或纸质版
<table border="1">
<caption>学生信息caption>
<thead>
<tr>
<th>姓名th>
<th>性别th>
<th>年龄th>
<th>民族th>
<th>政治面貌th>
tr>
thead>
<tbody>
<tr>
<td>张三td>
<td>男td>
<td>18td>
<td>汉族td>
<td>团员td>
tr>
<tr>
<td>李四td>
<td>女td>
<td>20td>
<td>满族td>
<td>群众td>
tr>
tbody>
<tfoot>
<tr>
<td>td>
<td>td>
<td>td>
<td>td>
<td>共计:4人td>
tr>
tfoot>
table>
表示文档中的一个区域,此区域包含交互控件,用于向 Web 服务器提交信息
<form action="https://search.jd.com/search">
用户名:
<input name="userName" value="hwm" disabled>
性别:
<input type="radio" name="gender" value="male" checked>男
<input type="radio" name="gender" value="female">女
<br>
爱好:
<input type="checkbox" name="hobby" value="smoke" checked>抽烟
<input type="checkbox" name="hobby" value="drink">喝酒
<input type="checkbox" name="hobby" value="perm">烫头
<br>
其它:
<textarea name="other" cols="23" row="3">textarea>
<br>
籍贯:
<select name="place">
<option value="湘" selected>湖南option>
<option value="粤">广东option>
<option value="鲁">山东option>
select>
<br>
用户不可见区域:
<input type="hidden" name="tag" value="abc">
<br>
<input type="submit" value="提交">
<input type="reset" value="重置">
<button type="button">普通按钮button>
form>
<fieldset>
<legend> ... legend>
...
fieldset>
<textarea name="other" cols="23" row="3">textarea>
<select name="place">
<option value="湘" selected>湖南option>
<option value="粤">广东option>
<option value="鲁">山东option>
select>
<br>
<hr>
<pre>
<iframe src="https://cn.bing.com/" width="1920" height="1080" frameborder="0">
iframe>
参考链接
id
给标签指定唯一标识,id 不可重复
作用:可让标签相关联
注意:,,,
h1 {
color: red;
font-size: 40px;
}
h2 {
color: green;
font-size: 60px;
}
行内样式:写在标签内,只对改标签生效
内部样式:写在 html 文件 内,对整个 html 文件生效
外部样式:将 css 样式单独写在一个 .css 文件中,在 html 中使用 标签链接优先级:行内 > 内部样式 = 外部样式 (后渲染的覆盖前渲染的)
通配选择器
* {
属性名: 属性值;
}
元素选择器
/* 为页面某种元素统一设置样式 */
标签名 {
属性名: 属性值;
}
类选择器
/* 为页面所有类名为 className 的元素设置样式 */
.className {
属性名: 属性值;
}
为标签同时设置两个类
<p class="fish animal">
id 选择器
#IDName {
属性名: 属性值;
}
/* html */
"idName">id 选择器
交集选择器
5.1 元素选择器 & 类选择器
标签名.className {
属性名: 属性值;
}
并集选择器
,类选择器
,元素选择器
,id 选择器 {
属性名: 属性值;
}
后代选择器(子类,子类的子类)
父元素 后代元素 {
属性名: 属性值;
}
子代选择器
父元素>子元素 {
属性名: 属性值;
}
兄弟选择器
/* 往下找紧紧相邻的兄弟元素 */
元素 + 兄弟元素 {
属性名: 属性值;
}
/* 元素后所有兄弟元素 */
元素 ~ 兄兄弟元素 {
属性名: 属性值;
}
属性选择器
/* 1.选中具有 title 属性的元素 */
[title] {
属性名: 属性值;
}
/* 2.选中具有 title 属性,且 title 属性为 "tt" 的元素 */
[title="tt"] {
属性名: 属性值;
}
/* 3.选中具有 title 属性,且 title 属性为 "tt" 开头的元素 */
[title^="tt"] {
属性名: 属性值;
}
/* 4.选中具有 title 属性,且 title 属性为 "tt" 结尾的元素 */
[title$="tt"] {
属性名: 属性值;
}
/* 4.选中具有 title 属性,且 title 属性为包含 "tt" 的元素 */
[title*="tt"] {
属性名: 属性值;
}
动态伪类选择器
/* 和类相似,但不是类,元素特殊状态的一种描述 */
/*
link visited 是 的特有状态
focus 是表单类特有
*/
/* -------------------- 动态伪类 ---------------------- */
/* 没有访问过的 a 元素 */
a:link {
属性名: 属性值;
}
/* 访问过的 a 元素 */
a:visited {
属性名: 属性值;
}
/* 鼠标悬浮的 a 元素 */
a:hover {
属性名: 属性值;
}
/* 激活状态的 a 元素 */
a:active {
属性名: 属性值;
}
/* 获取焦点 */
input:focus {
属性名: 属性值;
}
/* -------------------- 结构伪类 ---------------------- */
/* 第一个子元素是否满足条件,满足渲染 */
div>p:first-child {
属性名: 属性值;
}
/* 最后一个子元素是否满足条件,满足渲染 */
div>p:last-child {
属性名: 属性值;
}
/* 第 n 个子元素是否满足条件,满足渲染,子元素从 1 开始计算*/
/* n 从 0 开始增加 */
div>p:nth-child(n) {
属性名: 属性值;
}
/* 只在指定类型中找,非此类型不参与 */
:fist-of-type
:last-of-type
:nth-of-type
/* -------------------- 否定伪类 ---------------------- */
:div>p:not(.fial) {
属性名: 属性值;
}
/* -------------------- UI伪类 ---------------------- */
:checked {
属性名: 属性值;
}
:disabled {
属性名: 属性值;
}
/* -------------------- 目标伪类 ---------------------- */
:target { /* 锚点指向的元素 */
属性名: 属性值;
}
/* -------------------- 语言伪类 标签 lang 属性 ---------------------- */
:lang(语言类型) {
属性名: 属性值;
}
/* -------------------- 伪元素(像元素,但不是,是元素中的一些特殊位置)选择器 ---------------------- */
/* 第一个字母 */
::first-letter {
属性名: 属性值;
}
/* 第一行 */
::first-line {
属性名: 属性值;
}
/* 选中的文字 */
::selection {
属性名: 属性值;
}
/* 提示颜色 */
::placeholder {
属性名: 属性值;
}
/* 在元素最前面 */
::before {
content: Y
属性名: 属性值;
}
/* 在元素最后面 */
::after {
content: Y
属性名: 属性值;
}
简单的:!important > 行内样式 > id 选择器 > 类选择器 > 元素选择器 > 通配选择器 > 继承样式
公式计算:
(a,b,c)
a:id 选择器个数
b:类,伪类,属性 选择器个数
c:元素,伪元素 选择器个数
从 a -> b -> c 依次比较,大的优先级高可在 vscode 中将鼠标放到选择器上查看
层叠性
继承性
元素自动拥有其父元素,或其祖先元素上设置的某些样式
规则:优先继承近的
常见可继承属性:text-?? font-?? line-?? color
可在 MDN 查看元素是否可继承
优先级
font-size 字体大小
font-family 字体
font-style 字体风格
font-weight 字体粗细
lighter 细的
normal 正常
bold 粗体
数字 100 -900(跟字体设计精度有关)
字体复合属性
body {
font: font-style font-weight font-size/line-height font-family;
}
color 文本颜色
/* color: red; */
/* color: rgb(255, 0, 0); */
/* color: rgba(255, 0, 0, 0.5); */
color: #ff0000;
文本间距
text-decoration 文本修饰
属性 | 说明 |
---|---|
overline | 上划线 |
underline | 下划线 |
line-through | 删除线 |
wavy | 波浪线 |
text-decoration: overline underline wavy blue 5px;
text-indent 文本缩进
text-indent: 40px;
文本对齐
text-align 水平对齐
left center right
line-height 行高
文本垂直对齐
顶部:默认
居中:单行文字:height = line-height
底部:单行文字:line-height = (height x 2) - font-size -x
vertical-align
参考 MDN
该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐。
只对行内元素、行内块元素和表格单元格元素生效:不能用它垂直对齐块级元素
块元素(block)
特点:
- 在页面独占一行
- 默认宽度:撑满整个父元素
- 默认高度:由内容撑开
- 可以通过 css 修改宽高
代表元素:
- 主体结构标签:
- 排版标签:
-
- 列表标签:
- 表格相关标签:
行内元素(inline)
特点:
- 在页面不独占一行
- 默认宽度:由内容撑开
- 默认高度:由内容撑开
- 无法通过 css 修改宽高
代表元素:
- 文本标签:br em strong sup sub del ins
行内块元素(inline-block)
特点:
- 在页面不独占一行
- 默认宽度:由内容撑开
- 默认高度:由内容撑开
- 可以通过 css 修改宽高
代表元素:
- 图片:
- 单元格:
- 表单控件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l27Gr60g-1689749017403)(C:\Users\cli08\AppData\Roaming\Typora\typora-user-images\image-20230712181229789.png)]
- content(内容):元素中的文本或后代元素都是它的内容
- padding(内边距):紧贴内容的补白区域
- border(边框):盒子的边距
- margin(外边框):盒子与外界的距离
盒子的大小 = content + 左右 padding + 左右 border
注意:外边距 margin 不会影响盒子的大小,但会影响盒子的位置
content
min-width,max-width,min-height,max-height
width,height
padding
padding-left…
padding:(上下)(左右) (上)(右)(下)(左)
注意:padding 不能为负数,行内元素上下内边距设置会不占位置
border
border-width,border-color,border-style
border:width,style,color
border-left-width…,border-left-colo…,border-left-style…
border-left…
margin
属性同 padding
- visibility:设置为隐藏元素占位
- display:设置为隐藏不占位
指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它
属性值:left | right
浮动后的特点
- 脱离文档流
- 默认宽高被内容撑开,可手动设置宽高
- 不会独占一行,能与其它元素公用一行
overflow: visible 可见
overflow: hidden 隐藏
overflow: scroll 滚动条
overflow: auto 超出显示滚动条overflow-x
overflow-y
产生原因:行内元素,行内块元素,彼此之间的换行会被浏览器解析为一个空白字符
解决方案:给父元素设置 font-size: 0,再给需要显示文字的元素单独设置字体大小
定位的元素层级较高
都写了定位,后写的层级高
left | top | right | bottom
特点:
- 参考系:相对于正常位置的偏移
- 不会脱离文档流,不会对其它元素产生影响
left | top | right | bottom
特点:
- 脱离文档流
- 绝对定位和浮动不能一起用
- 开启绝对定位后成为定位元素:宽高由内容撑开,宽高可更改
- 参考系:包含块
- 包含块:
- 对于没有脱离文档流的元素,包含块为其父元素
- 对于脱离文档流的元素,包含块是第一个拥有定位属性的祖先元素(如果内衣,包含块就是整个页面)
left | top | right | bottom
特点:
- 脱离文档流
- 参考系:视口,元素一直在视口中
- 不能和浮动同时使用
left | top | right | bottom(胶水生效位置)
特点:
- 不脱离文档流
- 参考系:离它最近的一个拥有“滚动机制的祖先元素”
- 可以和浮动一起设置(不推荐)
auto 默认 | 0 | 1 | 2
只能在设置了定位的元素上设置
box-sizing
border-box:设置的边框和内边距的值是包含在 width 内的,如果你将一个元素的 width 设为 100px,那么这 100px 会包含它的 border 和 padding
content-box:默认值。如果你设置一个元素的宽为 100px,那么这个元素的内容区会有 100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。
resize
both | horizontal | vertical | none 用于设置元素是否可调整尺寸,以及可调整的方向。
要设置 overflow
box-dhadow
/* x 偏移量 | y 偏移量 | 阴影颜色 */ box-shadow: 60px -16px teal; /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影颜色 */ box-shadow: 10px 5px 5px black; /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */ box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
opacity
透明度
background-orgin
背景图原点,起始点
padding-box | content-box | border-box
background-clip
对背景图修剪,显示背景图区域
padding-box | border-box | content-box | text
backgronud-size
背景图尺寸
宽高 | %% | contain(宽高等比例缩放,背景再重复) | cover(宽高等比例缩放,宽或高自适应后截取)
column-count:直接指定列数
column-width:指定每列宽度
cloumn-gap:列间距
column-rule:边框像素,样式,颜色
column-span:跨列
特点:子元素块状化,变为块元素
属性值:display:flex(弹性布局) | inline-flex(不常用)
主轴方向
flex-direction:row(行,左到右) | column(列,上到下) | row-reverse(右到左) | column-reverse(下到上)
主轴换行方式
flex-wrap:nowrap(不换行,压缩子元素) | wrap(自动换行,副轴平分空间) | wrap-reverse(反向换行)
主轴对齐方式
justify-content:
- flex-start:主轴起始位置
- flex-end:主轴结束位置
- center:中间对齐
- space-around:子项均匀分布,子项与子项之间的距离,是子项与边缘之间距离的两倍
- space-between:子项均匀分布,子项与子项之间的距离是相等的,子项与边缘无距离
- space-evenly:子项均匀分布
侧轴对齐方式
单行:align-item:
- flex-start:侧轴起始位置对齐
- flex-end:侧轴结束位置对齐
- center:侧轴中间位置对齐
- stretch(默认值):拉伸到整个父容器
多行:align-content:
- flex-start:侧轴起始位置对齐
- flex-end:侧轴结束位置对齐
- center:侧轴中间位置对齐
- space-around:同主轴
- space-between:同主轴
- space-evenly:同主轴
- stretch(默认值):同侧轴
水平垂直居中
方案一: justify-content: center align-items:center 方案二: 父容器:display: flex 子项:margin:auto
给组件传值
<isLike :unlike="msgInfo.unlike" :like="msgInfo.like" :status="msgInfo.status" size="s" :faqID="faqID">isLike>
const props = defineProps({
// 踩
unlike:{
type:Number,
dafault:0
},
// 点赞
like:{
type:Number,
dafault:0
},
// 当前用户是否点赞
status:{
type:Number,
default:0
},
// 图标尺寸 S M
size:{
type:String,
default:'s'
},
//faqid
faqID:{
type:Number,
default:1
}
})
npm run dev
npm run dev --mode test
- 确定开发环境
.env.development 本地开发环境
.env.production 生产环境
.env.test 测试环境- 修改对应环境下的 VITE_BASE_URL
// 示例
interface msgListReq {
UpDown: number | null,
ID: number | null,
}
export const apiMsgList = (data: msgListReq) => {
return axios.request({
url: "/msg/list",
method: "post",
data
})
}
export const result = (data: {OrderID: number, Count: number}) => {
return axios.request({
url: "/order/info",
method: "post",
data,
})
}
// 使用
apiMsgList({UpDown: 0, ID: msgList.value[0].ID}).then(res => {
if(!res.data.List || res.data.List.length == 0) return // 历史消息为空,不处理
res.data.List.reverse()
msgList.value = [...res.data.List, ...msgList.value]
})
let scrollTop = document.documentElement.scrollTop;//滚动高度
let clientHeight = document.documentElement.clientHeight;//可视高度
let scrollHeight = document.documentElement.scrollHeight;//内容高度
function handleScroll(e:any) {
// 滚动条到顶部时,出现loading状态,接口请求完毕,关闭loading状态
if (msg.value!.scrollTop <= 0) {
scrollVal = msg.value!.scrollHeight // 记录下当前的滑动条高度
apiMsgList({ UpDown: 0, ID: msgList.value[0].ID }).then(res => {
show.value = true
if (!res.data.List || res.data.List.length == 0){ // 历史消息为空,不处理
show.value = false
return
}
setTimeout(() => {
res.data.List.reverse()
msgList.value = [...res.data.List, ...msgList.value]
nextTick(() => {
msg.value!.scrollTop = msg.value!.scrollHeight - scrollVal
show.value = false
})
}, 500);
})
} else {
show.value = false
}
}
nextTick(() => {
var targetDom: any = document.querySelector('.isActive')
var boxDom: any = document.querySelector('.main_left')
var st = targetDom.getBoundingClientRect().top
boxDom.scrollTop = boxDom.scrollTop + st - 75 - 70 - 15
})
data
Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化
: ‘ v m . : `vm. :‘vm.data访问原始数据对象。访问
vm.a等价于访问
vm. d a t a . a ‘ 。 v m . data.a`。 vm. data.a‘。vm.watch
el
只在用
new
创建实例时生效
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
<div id="root">
<h1>Hello, {{name.toUpperCase()}},{{age}},{{1+1}}h1>
<h1>学校:{{school.name}},地址:{{school.address}}h1>
div>
<script type="text/javascript">
Vue.config.productionTip = false // 阻止 vue 在启动时生成提示
// data 对象中的数据会做数据代理,既 get set,method 对象中的数据不会坐数据代理,里面存放方法
// method 中的方法不要用箭头函数,会导致 this 指向对象为 window (正常为 vm)
const x = new Vue({
el:'#root', // el 指定当前 vue 实例为哪个容器服务,值为 css 选择器
data:{ // data 用于存储数据,数据提供给 el 所指定的容器使用 {{name}}
name:"hwm",
age:18,
school:{
name:"hufe",
address:"changsha"
},
methods: {
showInfo1(event) {
console.log(this)
console.log(event)
},
showInfo2(event, num) {
console.log(event, num)
}
}
}
})
script>
插值语法
<h1>Hello, {{name.toUpperCase()}},{{age}},{{1+1}}h1>
data:{
name:"hwm",
age:18,
}
指令语法
v-bind(:):
单向绑定
响应式的更新html属性(在元素节点的属性上绑定 vue 的 data 数据)
语法糖:v-bind: 简写为 :
注意事项:v-bind: 后的 “” 中的值不是表示字符串,而是表示 vue 中的 data 中的属性
<a v-bind:href="url" target="_blank">点我,去百度a>
data:{
url:"http://www.baidu.com",
}
v-model(在表单中收集 value 值)
双向绑定
只能应用在表单类元素上
语法糖:省略 value, v-model=“”
修饰符:.number .lazy(失去焦点再收集) trim(去除前后空格)
<div id="root">
单向数据绑定:<input type="text" :value="iV1"/>br>
双向数据绑定:<input type="text" v-model="iV1"/>br>
修饰符:<input type="number" v-model.number="age"/>br>
<input type='text' v-model.lazy="age"/>br>
div>
data:{
iV1: "hwm",
},
// 第一种
new Vue({
el:"#root", // el 指定当前 vue 实例为哪个容器服务,值为 css 选择器
data:{ // data 用于存储数据,数据提供给 el 所指定的容器使用 {{name}}
name:"ming",
}
})
// 第二种
const vm = new Vue({
data(){
return {
name:"ming",
}
}
})
vm.$model("#root")
注意:通过此方法添加的属性,不在枚举内
定义(添加、修改)对象的属性
Object.defineProperty(对象,属性名,配置项(value))
let student = {
name:"ming",
sex:"男",
}
let num = 18
Object.defineProperty(student, "age", {
value:18,
enumerable: true, // 控制属性是否可枚举,默认 false
writable: true, // 控制属性是否可更改,默认 false
configurable: true, // 控制属性是否可删除,默认 false
get() { // 获取 age 属性时调用
return num
},
set(value) { // 设置 age 属性时调用
num = value
}
})
遍历获取到对象上的所有 key 属性
事件处理
v-on 可简写 @
new Vue({
el:"#root",
data() {
return {
}
},
methods: {
showInfo1(event) {
console.log(event)
},
showInfo2(event, num) {
console.log(event, num)
}
}
})
// 使用
/*
*/
- prevent:阻止默认事件
- stop:阻止事件冒泡(阻止一层冒泡)
- once:事件只触发一次
- capture:使用事件的捕获模式
- self:只有 event.target 是当前操作的元素时才触发事件
- passive:事件的默认行为立即执行,无需等待事件的回调执行完成
<button @click.once="addPerson">添加一个老刘button>
@keyup
@keydown
<input type="text" @keyup.enter="showInfo">
<button @click.once="addPerson">添加一个老刘button>
const vm = new Vue({
el: '#app',
data: {
firstName:"张",
lastName:"三",
},
methods: {
addPerson(e) {
console.log(e)
}
},
}
const vm = new Vue({
el: '#app',
data: {
firstName:"张",
lastName:"三",
},
methods: {
showInfo(e) {
console.log(e)
}
},
computed: {
fullName: {
// get 作用:当有人读取 fullName 时,get 就会被调用,且返回值就作为 fullname 的值
// 调用时机: 1.初次读取 fullname 时 2.所依赖的数据发生变化时
// this 指向 vm
get() {
return this.firstName + "-" + this.lastName
},
// 当 fullName 被修改时调用
set(value) {
const arr = value.split("-")
this.firstName = arr[0]
this.lastName = arr[1]
}
},
// 简写,当没有 set 函数时可简写成
fullName_simple() {
return this.firstName + "-" + this.lastName
},
}
})
<body>
<div id="app">
<h2>今天天气很{{info}}h2>
<button @click="showInfo">切换天气button>
<hr/>
<h3>a 的值是:{{numbers.a}}h3>
<button @click="numbers.a++">点我a + 1button>
div>
<script lang="ts">
const vm = new Vue({
el: '#app',
data: {
isHot: false,
numbers: {
a:1,
b:1,
},
},
methods: {
showInfo(e) {
this.isHot = !this.isHot
}
},
computed: {
info () {
return this.isHot ? "炎热" : "寒冷"
}
},
watch:{
// 可监视 vue 中的属性变化,也可监视计算属性中属性的变化
isHot: {
// immediate 为 true 时初始化时 handker 调用一次
immediate:true,
// handler 当 is hot 修改时调用,带两个参数:newValue:新的值,oldValue:旧的值
handler(newValue, oldValue) {
console.log("isHot 被修改了", newValue, oldValue)
}
},
// 简写形式
isHot(newValue, oldValue) {
console.log("isHot 被修改了", newValue, oldValue)
},
"numbers.a": {
handler(newValue, oldValue) {
console.log("numbers.a 被修改了", newValue, oldValue)
}
},
"numbers.b": {
handler(newValue, oldValue) {
console.log("numbers.b 被修改了", newValue, oldValue)
}
},
numbers: {
// immediate 为 true 监视多级结构中所有属性,默认为 false
deep: true,
handler(newValue, oldValue) {
console.log("numbers 被修改了", newValue, oldValue)
}
}
}
})
// vm.$watch('isHot', {
// immediate:true,
// handler(newValue, oldValue) {
// console.log("isHot 被修改了", newValue, oldValue)
// }
// })
script>
body>
<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>初始Vuetitle>
<script src="../js/vue.js">script>
<style>
.basic {
width: 100px;
height: 100px;
}
.normal {
background-color: aquamarine;
}
.happy {
background-color: hotpink;
}
.sad {
background-color: green;
}
.fontStyle1 {
font-size: 20px;
}
.fontStyle2 {
font-style: italic;
}
.fontStyle3 {
font-weight: bold;
}
style>
head>
<body>
<div id="app">
<div class="basic" :class="mood" @click="changeMood">{{name}}div>br>
<div class="basic" :class="fontStyles">{{name}}div>br>
<div class="basic" :class="classObj">{{name}}div>br>
div>
<script lang="ts">
const vm = new Vue({
el: '#app',
data: {
name:"hwm",
mood:"normal",
fontStyles:["fontStyle1", "fontStyle2", "fontStyle3", "normal"],
classObj: {
fontStyle1: false,
fontStyle2: false,
fontStyle3: false,
happy: false,
}
},
methods: {
changeMood() {
const moodArr = ["normal", "happy", "sad"]
let idx = Math.floor(Math.random()*3)
this.mood = moodArr[idx]
}
}
})
script>
body>
v-show
控制元素是否显示,设置元素 display 属性,
dom
元素依旧还在
v-if
控制元素是否显示,比 v-show 更彻底,
dom
元素整个添加或删除
v-else-if
v-else
注意点
v-if v-else-if v-else 组合使用时,元素要紧挨在一起
<div v-if="n===1">Angulardiv>
<div v-else-if="n===2">Reactdiv>
<div v-else-if="n===3">Vuediv>
<div v-else>mingdiv>
<template v-if="n===1">
<div>Angulardiv>
<div>Reactdiv>
<div>Vuediv>
template>
人员列表:
-
{{item.id}}-{{item.name}}-{{item.age}}
key 值得作用:
<body>
<div id="app">
<h2>人员列表:h2>
<input placeholder="请输入姓名" type="text" v-model="keyWord"/>
<button @click="sortType = 2">按年龄升序排列button>
<button @click="sortType = 1">按年龄降序排列button>
<button @click="sortType = 0">原序排列button>
<ul>
<li v-for="(item, index) in filtPersons" :key="item.id">
{{item.id}}-{{item.name}}-{{item.age}}-{{item.sex}}
li>
ul>
div>
<script lang="ts">
const vm = new Vue({
el: '#app',
data: {
sortType:"",
keyWord:"",
persons:[
{id:"001", name:"马冬梅", age:22, sex:"女"},
{id:"002", name:"周冬雨", age:19, sex:"女"},
{id:"003", name:"周杰伦", age:20, sex:"男"},
{id:"004", name:"温兆伦", age:21, sex:"男"},
],
},
methods: {
},
computed: {
filtPersons() {
console.log("访问了filtPersons")
let arr = this.persons.filter((elem => {
return elem.name.indexOf(this.keyWord) !== -1
}))
if(this.sortType) {
arr.sort((p1, p2) => {
return this.sortType === 1? p2.age - p1.age : p1.age - p2.age
})
}
return arr
}
},
})
script>
body>
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新
注意:注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
<script lang="ts">
const vm = new Vue({
el: '#app',
data: {
car: {
productionNum:"123456789",
struct:{
engine:"engine",
tyre:"tyre",
},
type:[
{name:"jeep", price:200},
{name:"bus", price:150},
{name:"moto", price:100},
]
}
},
methods: {
addCarPart(event, str) {
// Vue.set(this.car.struct, str, str)
this.$set(this.car.struct, str, str)
// 错误 this.$set(this, str, str)
// 删除属性
// Vue.delete(this.car.struct, str, str)
this.$delete(this.car.struct, str, str)
}
}
})
script>
vue 会监视 data 所有层次的数据
监测对象:
通过 settter 实现监视,且要在 new vue 时就传入要监测的数据
(1)对象后追加的属性,vue 默认不做响应式处理
(2)如需给后添加的属性做响应式,以下 API
Vue.set(target, propertyName/index, value)
Vue.set(target, propertyName/index, value)监测数组:
(1) 调用原生对应的方法对数组更新(push, pop, unshift, shift, splice, sort, reverse)
(2) 重新解析魔板,更新页面
错误:this.student.friends[0] = {…}
正确:this.student.friends[0].name = “”
<body>
<div id="app">
<form @submit.prevent="submit">
账号:<input type="text" v-model="userInfo.account"/>br>
密码:<input type="password" v-model="userInfo.password"/>
br>br>
性别:
<input type="radio" name="sex" value="male" v-model="userInfo.sex"/>男
<input type="radio" name="sex" value="female" v-model="userInfo.sex"/>女
br>br>
爱好:
<input type="checkbox" v-model="userInfo.hobby" value="smoke"/>抽烟
<input type="checkbox" v-model="userInfo.hobby" value="drink"/>喝酒
<input type="checkbox" v-model="userInfo.hobby" value="perm"/>烫头
br>br>
所属校区:
<select v-model="userInfo.city">
<option value="">请选择校区option>
<option value="beijing">北京option>
<option value="shanghai">上海option>
<option value="shenzhen">深圳option>
<option value="changsha">长沙option>
select>
br>br>
其它信息:
<textarea v-model="userInfo.other">textarea>
br>br>
<input type="checkbox" v-model="userInfo.agree"/>阅读并接受<a href="https://www.baidu.com">《用户协议》a>
br>br>
<button>提交button>
form>
div>
<script lang="ts">
const vm = new Vue({
el: '#app',
data: {
userInfo: {
account:'',
password:'',
sex:'male',
hobby:[],
city:'changsha',
other:'',
agree:'',
}
},
methods: {
submit() {
console.log(JSON.stringify(this.userInfo))
}
}
})
script>
body>
v-text:向其所在的节点中渲染文本内容,不支持标签文本解析
v-html:向其所在的节点中渲染文本内容,支持标签文本解析
v-cloak:没有值,vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性,配合 css 选择器使用
v-once:在初次动态渲染后,就视为静态内容(没有响应式)
v-pre:跳过所在节点的编译过程(可利用它跳过没有使用指令语法,插值语法的节点,加快编译)
命名规则:
错误:myCom: myCom
正确:‘myCom’: myCom
<body>
<div id="app">
<school>school>
br>
<student>student>
div>
<script lang="ts">
const school = {
template:`
学校名称:{{name}}
学校地址:{{address}}
`,
data() {
return {
name: "HUFE",
address: "长沙",
}
},
}
const student = {
template:`
学生名称:{{name}}
学生年龄:{{age}}
`,
data() {
return {
name: "ming",
age: 18,
}
},
}
const vm = new Vue({
el: '#app',
data: {
},
methods: {
},
components: {
school, // 简写 = school:school
student:student,
},
})
script>
body>
脚手架下载:vue2 文档 -> 生态系统 -> Vue CLI
基础样式:
<template>
<div class="demo">
<hello>hello>
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
<button @click="showName">点我提示学校名button>
div>
template>
<script>
// 组件交互相关代码(数据、方法等)
export default {
name:'MySchool',
data() {
return {
name: "HUFE",
address: "ChangSha"
}
},
methods: {
showName() {
alert(this.name)
}
}
}
script>
<style>
/* 组件样式 */
.demo {
background-color: orange;
}
style>
使用组件:
<template>
<div>
<img src="./assets/logo.png" alt="logo"/>
<School>School>
<Student name="ming" age="18" sex="男">Student>
div>
template>
<script>
// 引入组件
import School from "./components/School.vue";
import Student from "./components/Student.vue";
export default {
name:'App',
components: {
School,
Student,
}
}
script>
<style>
style>
用来给元素或子组件注册引用信息(id 的替代者)
应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc)
使用方式:
<h1 ref="xxx">h1> 或 <School ref="xxx">School>
this.$refs.xxx
props 主要用于组件的传值
props 定义的属性不要去修改
如果需要为 props 中的属性做响应式,可在 data 中声明属性并指向 props 中的属性
<template>
<div class="stu">
<hello>hello>
<h2 ref="title">学生姓名:{{stuName}}h2>
<h2>年龄:{{stuAge}}h2>
<h2>性别:{{sex}}h2>
<button @click="addAge">点我 age+1button>
div>
template>
<script>
// 组件交互相关代码(数据、方法等)
export default {
name:'MyStudent',
data() {
return {
stuName: this.name,
stuAge: this.age,
}
},
methods: {
addAge() {
this.stuAge++
}
},
// 写法一:无特殊限制,在使用组件时注意使用 v-bind(:)
// props:['name', 'age', 'sex'],
// 写法二:限制类型,使用组件传入值类型不对时会报错
// props: {
// name: String,
// age: Number,
// sex: String,
// }
// 写法三:限制类型,可选,默认值
props: {
name: {
type: String,
required: false, // 必须传的参数
},
age: {
type: Number,
default: 18, // 默认值
},
sex: String,
}
}
script>
<style>
/* 组件样式 */
.stu {
font-style: italic;
}
style>
<Student name="ming" :age="18+1" sex="男">Student>
提取 vc 对象中的公共属性实现在不同组件中复用
// 定义 mixin
export const h unhe = {
data: {
return{
x: 100,
y: 200,
}
}
methods: {
showName() {
alert(this.name)
}
},
mounted() {
console.log("mounted")
},
}
// 使用 mixin
<script>
import {hunhe} from ...
export default {
name:'',
data() {
return {
}
},
mixins:[hunhe]
}
</script>
<style scoped>
style>
[使用手册](Less 快速入门 | Less.js 中文文档 - Less 中文网 (bootcss.com))
[安装]((22条消息) Vue 安装 Less(CSS 预处理器)_vue中如何安装less_卡尔特斯的博客-CSDN博客)
<style lang="less">style>
安装router:npm install vue-router@3
基本用法:
router/index.ts:
import VueRouter from "vue-router";
import Login from '../components/Login.vue'
import Main from '../components/Main.vue'
import Register from '../components/Register.vue'
export default new VueRouter({
routes: [
{
path: '/login', // 跳转路径
name: 'login', // 名称
component: Login,
},
{
path: '/main', // 跳转路径
name: 'main', // 名称
component: Main,
},
{
path: '/register', // 跳转路径
name: 'register', // 名称
component: Register,
},
]
})
mian.js 中
Vue.use(VueRouter)
new Vue({
router,
render: h => h(App),
}).$mount('#app')
单个页面中(其它类似):
<template>
<h2>我是Login组件h2>
template>
<script>
export default {
name: 'Login',
}
script>
App.vue:
<template>
<div id="app">
<router-link to="/main">Mainrouter-link><br>
<router-link to="/login">Loginrouter-link><br>
<router-link to="/register">Registerrouter-link><br>
<router-view>router-view>
div>
template>
localStorage
在 Application -> Local storage 中查看
在清除浏览器缓存时会清空saveData() { localStorage.setItem("msg", "666") localStorage.setItem("person", JSON.stringify(this.p)) }, removeData() { // 清除某个缓存 localStorage.removeItem("msg") }, clearData() { // 清除所有缓存 localStorage.clear() }
sessionStorage
在 Application -> Session storage 中查看
关闭浏览器清空缓存
Api 同上,localStorage -> sessionStorage
vm. e m i t ( e v e n t , a r g ) / / 触发当前组件上的事件, e v e n t :事件名, a r g :参数 v m . emit(event, arg) // 触发当前组件上的事件,event:事件名,arg:参数 vm. emit(event,arg)//触发当前组件上的事件,event:事件名,arg:参数vm.on(event, fn) // 监听event事件后运行 fn
- 父组件可以使用 props 把数据传给子组件
- 子组件可以使用 $emit,让父组件监听到自定义事件
App.vue
{{ msg }}
通过父组件给子组件传递函数类型的 props 实现:子给父传数据:
学校名:{{ name }}
学校地址:{{ address }}
通过父组件给子组件绑定一个自定义事件实现:子给父传数据:
{{ msg }}
下一次 DOM 更新结束后执行器指定回调
this.$nextTick(function(){ this.$refs.inputTitle.focus() })
默认插槽
ming
默认值,组件使用者没传时显示
使用:
导入 .vue 组件
import Child from './components/Child.vue' // 不需要带 {}
通过 cli 创建 vue3 js 工程
- 查看 cli 版本,版本需在 4.5.0 以上
vue -V
npm install -g @vue/cli (默认安装最新版本cli)- 创建工程,选择 vue 版本
vue create vue3_test (工程名)
通过 cli 创建 vue3 ts 工程
通过 vite 创建 vue3 ts 工程
npm create vite@latest my-vue-app --template vue-ts
创建工程后使用:npm -i 安装模块
<template>
<h2>{{name}}h2>
<h2>{{age}}h2>
<button @click="sayHello">SayHellobutton>
template>
<script>
export default{
setup() {
let name = "ming"
let age = 18
function sayHello() {
alert(`Hello, I am ${name},my age is ${age}`)
}
return {
name,
age,
sayHello,
}
}
}
script>
setup 语法糖
<template>
<h2>{{name}}h2>
<h2>{{age}}h2>
<button @click="sayHello">SayHellobutton>
template>
<script setup>
let name = "ming"
let age = 18
function sayHello() {
alert(`Hello, I am ${name},my age is ${age}`)
}
script>
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>职位:{{ job.type }}h2>
<h2>薪水:{{ job.salary }}h2>
<button @click="fixName">点我修改名字button>
<br>
<button @click="fixAge">点我修改年龄button>
<br>
<button @click="fixJob">点我修改工作button>
template>
<script setup>
import { ref } from 'vue';
// ref 处理基本类型
let name = ref("ming")
let age = ref(18)
// ref 处理对象
let job = ref ({
type: "前端工程师",
salary: "30k",
})
function fixName() {
name.value = "hhh"
}
function fixAge() {
age.value = 20
}
function fixJob() {
job.value.type = "UI工程师"
job.value.salary = "50k"
}
script>
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>职位:{{ job.type }}h2>
<h2>薪水:{{ job.salary }}h2>
<h2>修改深层次对象属性:{{ job.a.b.c }}h2>
<h2>爱好:{{ hobby }}h2>
<button @click="fixName">点我修改名字button><br>
<button @click="fixAge">点我修改年龄button><br>
<button @click="fixJob">点我修改工作button><br>
<button @click="fixHobby">点我修改爱好button>
template>
<script setup>
import { reactive, ref } from 'vue';
// ref 处理基本类型响应式
let name = ref("ming")
let age = ref(18)
// reactive 处理对象响应式
let job = reactive ({
type: "前端工程师",
salary: "30k",
// 测试深层次
a: {
b: {
c: 666
}
}
})
// reactive 处理对象(数组)响应式
let hobby = reactive(['抽烟', '喝酒', '烫头'])
function fixName() {
name.value = "hhh"
}
function fixAge() {
age.value = 20
}
function fixJob() {
job.type = "UI工程师"
job.salary = "50k"
job.a.b.c = 999
}
function fixHobby() {
hobby[0] = '学习'
}
script>
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>性别:{{ person.sex }}h2>
<button @click="addInfo">添加信息button><br>
<button @click="delInfo">删除信息button><br>
template>
<script setup>
import { reactive, } from 'vue';
let person = reactive({
name: "ming",
age: 18
})
function addInfo() {
person.sex = "男"
}
function delInfo() {
delete person.name
}
script>
<template>
姓:<input type="text" v-model="person.firstName"/><br>
名:<input type="text" v-model="person.lastName"/><br>
名:<input type="text" v-model="person.fullName"/><br>
template>
<script setup>
import { reactive, computed} from 'vue';
let person = reactive({
firstName: "ming",
lastName: "ming",
})
// 简写,没有 setter
// let fullName = computed(() => {
// return person.firstName + '-' + person.lastName
// })
// 完整写法
person.fullName = computed({
get() {
return person.firstName + '-' + person.lastName
},
set(value) {
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
script>
<template>
<h2>num:{{ num }}h2>
<button @click="num++">点我num+1button><br>
<h2>num:{{ str }}h2>
<button @click="str+='!'">点我str+!button><br>
<h2>姓名{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.salary }}h2>
<button @click="person.name+='~'">点我修改姓名button>
<button @click="person.age++">点我修改年龄button>
<button @click="person.job.salary++">点我修改薪资button>
template>
<script setup>
import {ref, reactive, computed, watch} from 'vue';
let num = ref(0)
let str = ref("Hello")
let person = reactive({
name: "ming",
age: 18,
job: {
type: "前端工程师",
salary: "20",
}
})
// 情况一:监视一个 ref 所定义的响应式数据
// watch(num, (newV, oldV) => {
// console.log(`newV${newV},old:${oldV}`)
// }, {immediate: true})
// 情况二:监视多个 ref 所定义的响应式数据 newV:[newNum, newStr] oldV:[oldNum, oldStr]
// watch([num, str], (newV, oldV) => {
// console.log(newV,oldV)
// })
/* 情况三:监视 reactive 所定义的一个响应式数据,
踩坑点:
1. 无法正确获取 oldValue
2. 强制开启了深度监视(deep 配置无效)
*/
// watch(person, (newV) => {
// console.log('person 变化了', newV)
// })
// 情况四:监视 reactive 所定义的一个响应式数据的某个属性
watch(() => person.age, (newV, oldV) => {
console.log('person.age 变化了', newV, oldV)
})
script>
/*
1.初始就会执行一次
2.监视函数体中使用到某个属性,若该属性改变了就会执行一次
*/
watchEffect(() => {
console.log("watchEffect 调用了")
let x = num.value
let y = person.job.salary
})
图:官网查看
beforeCreate == setup()
beforeCreate == setup()
创建一个 usePoints.js 代码
import { onBeforeUnmount, onMounted, reactive } from "vue";
export default function() {
// 实现竖版“打点”相关数据
let point = reactive({
x:0,
y:0,
})
// 实现鼠标“打点”相关方法
function savePoint(event) {
point.x = event.pageX
point.y = event.pageY
console.log(event.pageX, event.pageY)
}
// 实现鼠标“打点”相关的生命周期狗子
onMounted(() => {
window.addEventListener('click', savePoint)
})
onBeforeUnmount(() => {
window.removeEventListener('click', savePoint)
})
return point
}
在组件中复用:
<template>
<div class="demo">
<h2>鼠标点击X坐标:{{ point.x }}h2>
<h2>鼠标点击Y坐标:{{ point.y }}h2>
div>
template>
<script setup>
import usePoint from '../hook/usePoints'
let point = usePoint()
script>
<style scoped>
/* 组件样式 */
.demo {
background-color: orange;
}
style>
- toRef: 复制 reactive 里的单个属性并转成 ref
- toRefs: 复制 reactive 里的所有属性并转成 ref
<template>
<h2>
reactive-greet: {{ info.greet }}
h2>
<h2>
toRef-greet: {{ rGreet }}
h2>
<button @click="onChangeGreet">更换问候语button>
template>
<script>
import { reactive, toRef } from 'vue'
export default {
setup() {
let info = reactive({
name: 'Tony',
greet: 'Hello'
})
// 复制整个 info
let rInfo = toRefs(info)
// 复制 info 里的 greet 属性
let rGreet = toRef(info, 'greet')
// 更改 rGreet
const onChangeGreet = () => {
rGreet.value = 'world!'
}
return {
info,
rGreet,
onChangeGreet
}
}
}
script>
只处理对象最外层属性的响应式(浅响应式)
- readonly: 让一个响应式数据变为只读的(深只读)。
- shallowReadOnly: 让一个响应式数据变为只读的(浅只读)
- toRaw : 将一个 reactive 生成的响应式对象转为普通对象
- markRaw: 标记一个对象,使其永远不会再成为响应式对象
作用:实现祖孙间通信
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXKRhQah-1689749017405)(C:\Users\cli08\AppData\Roaming\Typora\typora-user-images\image-20230530234850863.png)]
<script setup>
let car = {
name: "奔驰",
price: "70w"
}
provide('car', car)
components:{Child}
script>
<script setup>
let car = inject('car')
components:{Son}
script>
<template>
<div class="son">
<h3>我是孙组件 {{ car.name }}---{{ car.price }}h3>
div>
template>
<script setup>
import { inject } from 'vue';
let car = inject('car')
script>
isRef
,是否是由ref
定义的响应式数据isReactive
,是否是由reactive
定义的响应式数据isReadonly
,是否是由readonly
定义的数据isProxy
,是否是由reactive
或readonly
定义的数据
- 安装:npm install vue-router@4
- useRouter:对路由的控制,用来路由跳转
useRoute:路由的信息,用来路由传参
使用示例
单个页面(Login.vue 和 Main.vue):
<template>
<h2>我是Login组件h2>
template>
<script setup>
script>
Game.vue
我是Game组件
Game_1
Game_2
Game_3
Game_1.vue(Game_2.vue, Game_3.vue 类似)
我是Game_1组件
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.ts'
createApp(App).use(router).mount('#app')
router/index.ts
// history模式
import {createRouter, createWebHashHistory, RouteRecordRaw} from 'vue-router'
const routes : RouteRecordRaw[] = [
{
path: '/login', // 跳转路径
name: 'login', // 名称
component: () => import('../components/Login.vue'),
},
{
path: '/main', // 跳转路径
name: 'main', // 名称
component: () => import('../components/Main.vue'),
},
{
path: '/game', // 跳转路径
name: 'game', // 名称
component: () => import('../components/Game.vue'),
children:[
{
path: 'game_1',
name: 'game_1',
component: () => import('../components/Game_1.vue'),
},
{
path: 'game_2',
name: 'game_2',
component: () => import('../components/Game_2.vue'),
},
{
path: 'game_3',
name: 'game_3',
component: () => import('../components/Game_3.vue'),
},
]
},
]
// 创建路由对象
const router = createRouter({
history: createWebHashHistory(),
routes,
})
export default router
App.vue
Main
Login
Register
路由传参
query
Main
param
Login
编程式路由导航
const router = useRouter()
// 跳转页面
router.push('path', query: {}) // 压入历史记录栈顶
router.push(name: 'name', param: {}) // 压入历史记录栈顶
router.replace('path', query: {}) // 替换历史记录栈顶
router.replace(name: 'name', param: {}) // 替换历史记录栈顶
router.go(1) // 向前移动一条历史记录
router.go(-1) // 向后移动一条历史记录
安装 pinia :npm install pinia
修改main.js,引入pinia提供的createPinia方法,创建根存储。
// main.ts import { createApp } from "vue"; import App from "./App.vue"; import { createPinia } from "pinia"; const pinia = createPinia(); const app = createApp(App); app.use(pinia); app.mount("#app");
src 下创建文件夹 store,用来存放共享数据
创建 store
import { defineStore } from 'pinia'
import { reactive } from 'vue';
interface Student {
name: string,
age: number,
sex: string,
job: {
type: string,
salary: string,
}
}
export const useUsersStore = defineStore("users", () => {
const student = reactive<Student>({
name: 'ming',
age: 18,
sex: '男',
job: {
type: '前端工程师',
salary: '30k',
}
})
const addAge = (add: number) => {
student.age += add
}
return {
student,
addAge
};
});
使用
姓名:{{ student.name }}
年龄:{{ student.age }}
性别:{{ student.sex }}
职位:{{ student.job.type }}
薪水:{{ student.job.salary }}