vue(html,css,vue2,vue3) 学习总结

文章目录

  • 小白 Vue 3 学习
    • 一些名词
    • 软件安装
  • VSCode 中的一些设置
    • 1. 关闭eslint检查
    • tsconfig.json 配置文件
    • 2. ts 文件引用报红
  • 相对路径写法
  • 常见图片格式和区别
  • 目录结构
  • JS/TS
    • 1. prototype(原型对象)
    • 2. 导入/导出
    • 3. 去除字符串两端空格
    • 4. 一些特殊语法糖
    • 5. 深拷贝
    • 6. 拼接两个数组
    • 7. JSON
  • DOM
    • 一些常用属性
  • HTML
    • 结构代码展示
    • 块级元素与行内元素
    • 标签参考
      • 容器标签
      • 1. 文本标签
      • 2. 图片标签
      • 3. 超链接
      • 4. 列表
      • 5. 表格
      • 6. 表单
      • 7. 输入框
      • 8.文本域
      • 9.下拉框
      • 10.label 标签
      • 11.补充常用标签
      • 12.框架标签
      • 13.字符实体
    • 全局属性
  • CSS
    • 样式
    • 选择器
    • 选择器优先级
    • CSS 三大特性
    • 字体属性
    • 文本属性
    • 列表属性
    • 边框属性
    • 表格属性
    • 背景属性
    • 鼠标相关属性
    • 长度单位
    • 元素的显示模式
    • 修改元素显示模式
    • 盒子模型的组成部分
    • 隐藏元素的方式
    • float 浮动
    • overflow 处理内容溢出
    • 元素之间的空白问题
    • position 定位
      • relative 相对定位
      • absolute 绝对定位
      • fixed 固定定位
      • sticky 粘性定位
      • z-index 定位的层级
  • CSS3
    • 长度单位
    • 新增盒子属性
    • 新增背景属性
    • 多列布局
    • 弹性布局
  • cas_websited
    • 0. 项目中学到的一些技巧
    • 1. 指令
    • 2. 协议对接
    • 3. 请求服务器
    • 4. 上拉加载历史消息(滑动条保持原高度)
    • 5. 滑动条定位
  • Vue 2
    • 0. 总结
    • 1. 初识 vue
    • 2. 模板语法(V-bind,v-model)
    • 3. vue 实例两种写法
    • 4. Object.defineProperty() 给对象添加属性
    • 5. Object.keys(对象)
    • 6. v-on(事件处理)
    • 7. 事件修饰符
    • 8. 键盘事件
    • 9. methods(方法)
    • 10. computed(计算属性)
    • 11. watch(监视属性)
    • 12. 绑定样式
    • 13. 条件渲染(v-show/v-if/v-else-if/v-else)
    • 14. v-for (列表渲染)
    • 15. 列表过滤和排序
    • 16. set(object, key, value) 添加响应式属性
    • 17. vue 监测数据总结
    • 18. 收集表单数据示例
    • 19. vue 内部指令
    • 20. 生命周期
    • 21. 非单文件组件
    • 22. vm 与 vc
    • 23. 单文件组件(.vue)
    • 24. ref 属性
    • 25. props 属性(父传子)
    • 26. mixin(混合)
    • 27. scoped(局部样式)
    • 28. less
    • 29. 路由
    • 30. 浏览器本地存储
    • 31. $emit $on 组件自定义事件(子传父)
    • 32. nextTick()
    • 33. 插槽
  • Vue 3
    • 注意事项
    • 0. 创建 vue3 工程
    • 1. setup 函数
    • 2. ref 函数(为数据做响应式)
    • 3. reactive 函数(处理对象响应式)
    • 4. 新增/删除属性
    • 5. computed 计算属性
    • 6. watch 数据监视
    • 7. watchEffect
    • 8. 生命周期
    • 9. hook (复用代码)
    • 10. toRef 和 toRefs
    • 11. shallowReactive
    • 12. readonly 和 shallowReadOnly
    • 13. toRaw 和 markRaw
    • 14. provide 和 inject
    • 15.响应式数据判断
    • 16. Router (路由)
    • 17. pinia 状态管理器使用
    • 18. ref 获取 DOM 元素

小白 Vue 3 学习

一些名词

  • Node.js

    Node.js 是一个基于 Chrome V8 引擎的 Javascript 运行环境

  • NPM (Node Package Manager)

    软件包仓库

软件安装

  • Node
    Node.js 安装配置 | 菜鸟教程 (runoob.com)

VSCode 中的一些设置

1. 关闭eslint检查

在 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  /* 禁止对同一文件的大小写不一致的引用。 */
}
}

2. ts 文件引用报红

在 src 下创建文件 vite-env.d.ts

/// <reference types="vite/client" />

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 视图

JS/TS

1. prototype(原型对象)

类似于继承,所有对象上都有 [[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

2. 导入/导出

  1. 导出

    ①默认导出:export default Test(导入时可指定模块任意名称,无需知晓内部真实名称)
    ②单独导出:export const name = "Bruce"
    ③按需导出:export { age, name, sex }(推荐)
    ④改名导出:export { name as newName }
    
  2. 导入

    ①默认导入:import Test from "test"
    ②整体导入:import * as Test from "test"
    ③按需导入:import { age, name, sex } from "test"
    ④改名导入:import { name as newName } from "test"
    

3. 去除字符串两端空格

//trim()例子
let str = ' hello '
console.log(str.trim()) //hello

4. 一些特殊语法糖

  1. !

    非空断言操作符
    用于断言操作对象是非 null 和非 undefined 类型

    type HandleChange= () => void;
    
    function myFunc(onChange: HandleChange | undefined) {
    	//如果不加!,会报错
    	const a = onChange(); // Error
    	const b = onChange!(); //OK
    }
    
  2. ?.

    遇到 null 或 undefined 就可以立即停止表达式的运行

  3. ??

    当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数

    console.log(false ?? '哈哈哈')  // false
    console.log(null ?? '哈哈哈')  // 哈哈哈
    

5. 深拷贝

let deepObj = JSON.parse(JSON.stringify(obj));

6. 拼接两个数组

let arr = [1, 2]
let arr2 = [3, 4]

arr = [...arr, ...arr2]

console.log(arr)
// [1, 2, 3, 4]

7. JSON

  • 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"}
    

DOM

一些常用属性

  1. scrollTop, scrollHeight, clientHeight

    • scrollTop:元素顶部到元素可视区域顶部的像素距离(可读写)。
    • scrollHeight:类似于clientHeight,但包括由于overflow属性不可见内容的高度。
    • clientHeight:元素的像素高度,包括盒子内容content和内边距padding, 不包括边框外边距和水平滚动条(只读)

    滚动到底部判断:element.scrollHeight-element.scrollTop=element.clientHeight

HTML

结构代码展示

<!-- 在 VSCode 中键入一个 '!' 回车可自动补齐 -->

<!DOCTYPE HTML> <!-- HTML5标准网页声明 -->
<HTML lang="en"> <!-- HTML为根标签,代表整个网页  zh-CN -->

<head> <!-- head为头部标签,一般用来描述文档的各种属性和信息, 包括标题等-->
  <meta charset="UTF-8"> <!-- 设置字符集为utf-8 -->
  <title>my HTML</title> <!-- 设置浏览器的标题 -->
</head>

<!-- 网页所有的内容都写在body标签内 -->
<body> 
  我的第一个HTML网页
</body>

</HTML>

块级元素与行内元素

块级元素:独占一行,块级元素内能写任何元素

行内元素:不独占一行,行内元素内能写行内元素,但不能写块级元素

标签参考

容器标签

<div> </div>

1. 文本标签

常用:

em用户着重阅读的内容
strong表示文本十分重要,一般用粗体显示
span元素是短语内容的通用行内容器,并没有任何特殊语义。

不常用:

cite表示一个作品的引用,且必须包含作品的标题
dfn特殊术语,或专属名词
del 与 ins删除的文字内容【与】插入文档中的文本
sub 与 sup下标文字【与】上标文字
code一段代码
samp标识计算机程序输出
kbd键盘输入元素,用于表示用户输入
addr联系信息,说明,配合 title 属性使用
bdo改写了文本的方向性,配合 dir 属性使用
var变量
address某个人或某个组织(等等)的联系信息。

2. 图片标签

标签名属性说明
imgsrc(相对路径),alt(图像描述,利于搜索)单标签

3. 超链接

标签名属性说明
imghref(跳转网址),target(新页面从哪打开) download=“name”(将链接的 URL 视为下载资源)单标签,超链接

通过超链接跳转锚点:

<body>
    <a href="#5">测试超链接跳转锚点</a>
    <p>我是锚点1</p>
    <p>我是锚点2</p>
    <p>我是锚点3</p>
    <p>我是锚点4</p>
    <p id="5">我是锚点5</p>
</body>

<a href="#">回到顶部</a> <!-- 回到顶部 -->

超链接唤起指定应用:

<!-- 唤起设备拨号 -->
<a href="tel:10086">电话联系</a>
<!-- 唤起设备发送邮件 -->
<a href="mailto:10086@qq.com">邮件联系</a>
<!-- 唤起设备发送短信 -->
<a href="sms:10086">短信联系</a>

4. 列表

  • 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>
    
  • 注意点

    1. 列表可嵌套使用

      <ul>
          <li>云南</li>
          <li>成都</li>
          <li>
              <span>上海</span>
              <ul>
                  <li>外滩</li>
                  <li>东方明珠</li>
                  <li>迪士尼乐园</li>
              </ul>
          </li>
      </ul>
      
    2. 自定义列表一个术语可有多个描述

      <dl>
          <dt>做好笔记</dt>
          <dd>好记性不如烂笔头</dd>
      	<dd>笔记可以是电子版或纸质版</dd>
      </dl>
      

5. 表格

<!-- 
table属性:  border:外边框厚度  weight,height:宽高,不影响表头和脚注 cellspacing:边框间距离
thead属性:  allign:水平布局方式  vallign:垂直布局方式
tbody属性: 
tfoot属性:
th属性:	  colsspan:跨列  rowspan:跨行
-->
<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>18</td> 
            <td>汉族</td> 
            <td>团员</td> 
        </tr>

        <tr>
            <td>李四</td>
            <td></td> 
            <td>20</td> 
            <td>满族</td> 
            <td>群众</td> 
        </tr>
    </tbody>

    <!-- 表格脚注 -->
    <tfoot>
        <tr>
            <td></td>     <!-- 表体单元格 -->
            <td></td>
            <td></td>
            <td></td>
            <td>共计:4人</td>
        </tr>
    </tfoot>
</table>

6. 表单

表示文档中的一个区域,此区域包含交互控件,用于向 Web 服务器提交信息

<!-- 属性:action:表单提交地址, -->
<form action="https://search.jd.com/search">
    用户名:<!-- 禁用 -->
    <input name="userName" value="hwm" disabled>
    性别:<!-- 单选框 -->
    <input type="radio" name="gender" value="male" checked><!-- 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>

7. 输入框

<!-- 属性
type:类型  value:默认值  maxlength:最大输入长度
-->

8.文本域

<textarea name="other" cols="23" row="3"></textarea>

9.下拉框

<select name="place">
    <option value="" selected>湖南</option>
    <option value="">广东</option>
    <option value="">山东</option>
</select>

10.label 标签

<!-- 表示用户界面中某个元素的说明 -->

11.补充常用标签

<!-- 换行标签 -->
<br>

<!-- 分割线 -->
<hr>

<!-- 按原文显示 -->
<pre>

12.框架标签

<!-- 将另一个 HTML 页面嵌入到当前页面中 -->
<!-- 可用 name 属性与<a>或<form>的 target 属性配合使用 -->
<iframe src="https://cn.bing.com/" width="1920" height="1080" frameborder="0">
</iframe>

13.字符实体

参考链接

全局属性

  1. id

    给标签指定唯一标识,id 不可重复
    作用:可让标签相关联
    注意:,,,

CSS

h1 {
    color: red;
    font-size: 40px;
}
h2 {
    color: green;
    font-size: 60px;
}

样式

行内样式:写在标签内,只对改标签生效
内部样式:写在 html 文件 内,对整个 html 文件生效
外部样式:将 css 样式单独写在一个 .css 文件中,在 html 中使用 标签链接

优先级:行内 > 内部样式 = 外部样式 (后渲染的覆盖前渲染的)

选择器

  1. 通配选择器

    * {
        属性名: 属性值;
    }
    
  2. 元素选择器

    /* 为页面某种元素统一设置样式 */
    标签名 {
        属性名: 属性值;
    }
    
  3. 类选择器

    /* 为页面所有类名为 className 的元素设置样式 */
    .className {
        属性名: 属性值;
    }
    

    为标签同时设置两个类

    <p class="fish animal">
    
  4. id 选择器

    #IDName {
        属性名: 属性值;
    }
    
    /* html */
    <h1 id="idName">id 选择器</h1>
    
  5. 交集选择器
    5.1 元素选择器 & 类选择器

    标签名.className {
        属性名: 属性值;
    }
    
  6. 并集选择器

    ,类选择器
    ,元素选择器
    ,id 选择器 {
        属性名: 属性值;
    }
    
  7. 后代选择器(子类,子类的子类)

    父元素 后代元素 {
        属性名: 属性值;
    }
    
  8. 子代选择器

    父元素>子元素 {
        属性名: 属性值;
    }
    
  9. 兄弟选择器

    /* 往下找紧紧相邻的兄弟元素 */
    元素 + 兄弟元素 {
        属性名: 属性值;
    }
    
    /* 元素后所有兄弟元素 */
    元素 ~ 兄兄弟元素 {
        属性名: 属性值;
    }
    
  10. 属性选择器

    /* 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"] {
        属性名: 属性值;
    }
    
  11. 动态伪类选择器

    /* 和类相似,但不是类,元素特殊状态的一种描述 */
    
    /*
    link visited 是 <a> 的特有状态 
    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 中将鼠标放到选择器上查看

CSS 三大特性

  • 层叠性

  • 继承性

    元素自动拥有其父元素,或其祖先元素上设置的某些样式
    规则:优先继承近的
    常见可继承属性:text-?? font-?? line-?? color
    可在 MDN 查看元素是否可继承

  • 优先级

字体属性

  1. font-size 字体大小

    • 可以给 body 指定整个页面的文字大小
    • 可在 设置 -> 外观 中调整字体最小字号和字体默认大小
  2. font-family 字体

  3. font-style 字体风格

    • italic 斜体
    • normal 正常
  4. font-weight 字体粗细

    • lighter 细的

    • normal 正常

    • bold 粗体

    • 数字 100 -900(跟字体设计精度有关)

  5. 字体复合属性

    body {
    		font: font-style font-weight  font-size/line-height font-family;
    }
    
    • 使用 font 属性时,必须按上面的语法格式中的顺序书写,不得更换顺序,并且各个属性间以空格隔开。
    • 不需要设置的属性可以省略(取默认值),但必须保留 font-size 和 font-family 属性,否则 font 属性不起作用。

文本属性

  1. color 文本颜色

    /* color: red; */
    /* color: rgb(255, 0, 0); */
    /* color: rgba(255, 0, 0, 0.5); */
    color: #ff0000;
    
  2. 文本间距

    • letter-spacing 字符间距
    • word-spacing 单词间距(根据空格识别单词)
    • 可给负值,缩小字符间距
  3. text-decoration 文本修饰

    属性说明
    overline上划线
    underline下划线
    line-through删除线
    wavy波浪线
    text-decoration: overline underline wavy blue 5px;
    
  4. text-indent 文本缩进

    text-indent: 40px;
    
  5. 文本对齐

    • text-align 水平对齐
      left center right

    • line-height 行高

    • 文本垂直对齐

      顶部:默认

      居中:单行文字:height = line-height

      底部:单行文字:line-height = (height x 2) - font-size -x

  6. vertical-align

    参考 MDN
    该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐。
    只对行内元素、行内块元素和表格单元格元素生效:不能用它垂直对齐块级元素

列表属性

  1. list-style-type:列表符号
  2. list-style-position:指定标记框在主体块框中的位置
  3. list-style-image:自定义列表元素标记的图片

边框属性

  1. border-width
  2. border-style
  3. border-color
  4. border(复合属性)

表格属性

  1. table-layout:控制表格列宽
  2. border-spacing:控制单元格间距
  3. border-collapse:合并相邻单元格的边框

背景属性

  1. background-color:背景颜色,transparent
  2. background-image:会平铺整个区域
  3. background-repeat:设置背景图片的重复方式
  4. background-position:设置背景图片的位置

鼠标相关属性

  1. cursor:光标样式

长度单位

  1. px:像素
  2. em:相对于当前元素的 font-size 的倍数,先找父元素的 font-size,最后浏览器默认 font-size
  3. %:相对于父元素的百分比

元素的显示模式

  1. 块元素(block)

    特点:

    • 在页面独占一行
    • 默认宽度:撑满整个父元素
    • 默认高度:由内容撑开
    • 可以通过 css 修改宽高

    代表元素:

    • 主体结构标签:
    • 排版标签:

      -


       
             
             

    • 列表标签:
        1. 表格相关标签:
  2. 行内元素(inline)

    特点:

    • 在页面不独占一行
    • 默认宽度:由内容撑开
    • 默认高度:由内容撑开
    • 无法通过 css 修改宽高

    代表元素:

    • 文本标签:br em strong sup sub del ins
  3. 行内块元素(inline-block)

    特点:

    • 在页面不独占一行
    • 默认宽度:由内容撑开
    • 默认高度:由内容撑开
    • 可以通过 css 修改宽高

    代表元素:

    • 图片:
    • 单元格:
    • 表单控件:

修改元素显示模式

  • display
    block: 块元素,none:不显示,inline:行内元素,inline-block:行内块元素

盒子模型的组成部分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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

隐藏元素的方式

  1. visibility:设置为隐藏元素占位
  2. display:设置为隐藏不占位

float 浮动

指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它

属性值:left | right
浮动后的特点

  1. 脱离文档流
  2. 默认宽高被内容撑开,可手动设置宽高
  3. 不会独占一行,能与其它元素公用一行

overflow 处理内容溢出

overflow: visible 可见
overflow: hidden 隐藏
overflow: scroll 滚动条
overflow: auto 超出显示滚动条

overflow-x
overflow-y

元素之间的空白问题

产生原因:行内元素,行内块元素,彼此之间的换行会被浏览器解析为一个空白字符

解决方案:给父元素设置 font-size: 0,再给需要显示文字的元素单独设置字体大小

position 定位

定位的元素层级较高
都写了定位,后写的层级高

relative 相对定位

left | top | right | bottom

特点:

  • 参考系:相对于正常位置的偏移
  • 不会脱离文档流,不会对其它元素产生影响

absolute 绝对定位

left | top | right | bottom

特点:

  • 脱离文档流
  • 绝对定位和浮动不能一起用
  • 开启绝对定位后成为定位元素:宽高由内容撑开,宽高可更改
  • 参考系:包含块
  • 包含块:
    1. 对于没有脱离文档流的元素,包含块为其父元素
    2. 对于脱离文档流的元素,包含块是第一个拥有定位属性的祖先元素(如果内衣,包含块就是整个页面)

fixed 固定定位

left | top | right | bottom

特点:

  • 脱离文档流
  • 参考系:视口,元素一直在视口中
  • 不能和浮动同时使用

sticky 粘性定位

left | top | right | bottom(胶水生效位置)

特点:

  • 不脱离文档流
  • 参考系:离它最近的一个拥有“滚动机制的祖先元素”
  • 可以和浮动一起设置(不推荐)

z-index 定位的层级

auto 默认 | 0 | 1 | 2

只能在设置了定位的元素上设置

CSS3

长度单位

  1. vw:视口宽度的百分比
  2. vh:视口高度的百分比

新增盒子属性

  1. box-sizing

    border-box:设置的边框和内边距的值是包含在 width 内的,如果你将一个元素的 width 设为 100px,那么这 100px 会包含它的 border 和 padding

    content-box:默认值。如果你设置一个元素的宽为 100px,那么这个元素的内容区会有 100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。

  2. resize

    both | horizontal | vertical | none 用于设置元素是否可调整尺寸,以及可调整的方向。

    要设置 overflow

  3. 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);
    
  4. opacity

    透明度

新增背景属性

  1. background-orgin

    背景图原点,起始点
    padding-box | content-box | border-box

  2. background-clip

    对背景图修剪,显示背景图区域
    padding-box | border-box | content-box | text

  3. backgronud-size

    背景图尺寸
    宽高 | %% | contain(宽高等比例缩放,背景再重复) | cover(宽高等比例缩放,宽或高自适应后截取)

多列布局

column-count:直接指定列数
column-width:指定每列宽度
cloumn-gap:列间距
column-rule:边框像素,样式,颜色
column-span:跨列

弹性布局

特点:子元素块状化,变为块元素
属性值:display:flex(弹性布局) | inline-flex(不常用)

  1. 主轴方向

    flex-direction:row(行,左到右) | column(列,上到下) | row-reverse(右到左) | column-reverse(下到上)

  2. 主轴换行方式

    flex-wrap:nowrap(不换行,压缩子元素) | wrap(自动换行,副轴平分空间) | wrap-reverse(反向换行)

  3. 主轴对齐方式

    justify-content:

    1. flex-start:主轴起始位置
    2. flex-end:主轴结束位置
    3. center:中间对齐
    4. space-around:子项均匀分布,子项与子项之间的距离,是子项与边缘之间距离的两倍
    5. space-between:子项均匀分布,子项与子项之间的距离是相等的,子项与边缘无距离
    6. space-evenly:子项均匀分布
  4. 侧轴对齐方式

    单行:align-item:

    1. flex-start:侧轴起始位置对齐
    2. flex-end:侧轴结束位置对齐
    3. center:侧轴中间位置对齐
    4. stretch(默认值):拉伸到整个父容器

    多行:align-content:

    1. flex-start:侧轴起始位置对齐
    2. flex-end:侧轴结束位置对齐
    3. center:侧轴中间位置对齐
    4. space-around:同主轴
    5. space-between:同主轴
    6. space-evenly:同主轴
    7. stretch(默认值):同侧轴
  5. 水平垂直居中

    方案一:
    justify-content: center
    align-items:center
    方案二:
    父容器:display: flex
    子项:margin:auto
    

cas_websited

0. 项目中学到的一些技巧

  1. 给组件传值

    <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
        }
    })
    

1. 指令

npm run dev
npm run dev --mode test

2. 协议对接

  1. 确定开发环境
    .env.development 本地开发环境
    .env.production 生产环境
    .env.test 测试环境
  2. 修改对应环境下的 VITE_BASE_URL

3. 请求服务器

// 示例
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]
})

4. 上拉加载历史消息(滑动条保持原高度)

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
  }
}

5. 滑动条定位

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
})

Vue 2

0. 总结

  • 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.avm.watch

  • el

    只在用 new 创建实例时生效
    提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。

1. 初识 vue

<!-- 
    1.想让 Vue 工作,就必须创建一个 Vue 实例,且要传入一个配置对象
    2.root容器里的代码依然符合 html 规范,只不过混入了一些特殊的 Vue 语法
    3.root容器里的代码被称为 Vue 对象
    4.Vue 实例与容器一一对应
    5.真实开发中只有一个 Vue 实例,并且会配合组件一起使用
    6.容器中的 {{}} 可写 vue 实例中对象的属性或者 js 表达式
    7.data 中的数据发生改变,魔板中用到该数据的地方会自动更新
    8.在浏览器中可通过 vue.js devtools Root 中查看或临时更改 data 中的属性
	9.Vue 实例数据结构可嵌套
-->

<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>

2. 模板语法(V-bind,v-model)

  1. 插值语法

    <h1>Hello, {{name.toUpperCase()}},{{age}},{{1+1}}</h1>
    
    data:{
    	name:"hwm",
    	age:18,
    }
    
  2. 指令语法

    • v-bind(:):

      单向绑定
      响应式的更新html属性(在元素节点的属性上绑定 vue 的 data 数据)
      语法糖:v-bind: 简写为 :
      注意事项:v-bind: 后的 “” 中的值不是表示字符串,而是表示 vue 中的 data 中的属性

      <a v-bind:href="url" target="_blank">点我,去百度</a>
      <!-- vue 中的 date -->
      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",
      },
      

3. vue 实例两种写法

// 第一种
new Vue({
    el:"#root",     // el 指定当前 vue 实例为哪个容器服务,值为 css 选择器
    data:{          // data 用于存储数据,数据提供给 el 所指定的容器使用 {{name}}
    	name:"ming",
    }
})

// 第二种
const vm = new Vue({
    data(){
    	return {
            name:"ming",
        }
    }
})
vm.$model("#root")

4. Object.defineProperty() 给对象添加属性

注意:通过此方法添加的属性,不在枚举内
定义(添加、修改)对象的属性
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
    }
})

5. Object.keys(对象)

遍历获取到对象上的所有 key 属性

6. v-on(事件处理)

事件处理
v-on 可简写 @

new Vue({
    el:"#root",
    data() {
        return {

        }
    },
    methods: {
        showInfo1(event) {
            console.log(event)
        },
        showInfo2(event, num) {
            console.log(event, num)
        }
    }
})

// 使用
/* <div id="root">
    <button @click="showInfo1">Hello111(不传参,默认传event)</button>
	<button @click="showInfo2($event, 66)">Hello222(传参, $event 是默认值)</button>
</div> */

7. 事件修饰符

  1. prevent:阻止默认事件
  2. stop:阻止事件冒泡(阻止一层冒泡)
  3. once:事件只触发一次
  4. capture:使用事件的捕获模式
  5. self:只有 event.target 是当前操作的元素时才触发事件
  6. passive:事件的默认行为立即执行,无需等待事件的回调执行完成
<button @click.once="addPerson">添加一个老刘</button>

8. 键盘事件

@keyup
@keydown

<!-- 为提供别名的按键可使用按键原始的 key 绑定,两个单词组成的键要写为 caps-lock -->
<input type="text" @keyup.enter="showInfo">

9. methods(方法)

<button @click.once="addPerson">添加一个老刘</button>
const vm = new Vue({
    el: '#app',
    data: {
        firstName:"张",
        lastName:"三",
    },
    methods: {
        addPerson(e) {
            console.log(e)
        }
    },
}

10. computed(计算属性)

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
        },
    }
})

11. watch(监视属性)

<body>
    <!-- 
        1.想让 Vue 工作,就必须创建一个 Vue 实例,且要传入一个配置对象
        2.root容器里的代码依然符合 html 规范,只不过混入了一些特殊的 Vue 语法
        3.root容器里的代码被称为 Vue 对象
        4.Vue 实例与容器一一对应
        5.真实开发中只有一个 Vue 实例,并且会配合组件一起使用
        6.容器中的 {{}} 可写 vue 实例中对象的属性或者 js 表达式
        7.data 中的数据发生改变,模板中用到该数据的地方会自动更新
        8.在浏览器中可通过 vue.js devtools Root 中查看或临时更改 data
     -->

 
    <div id="app">
        <h2>今天天气很{{info}}</h2>
        <button @click="showInfo">切换天气</button>
        <hr/>
        <h3>a 的值是:{{numbers.a}}</h3>
        <button @click="numbers.a++">点我a + 1</button>
    </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>

12. 绑定样式

  • 绑定 class 样式
<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>初始Vue</title>
    <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>

13. 条件渲染(v-show/v-if/v-else-if/v-else)

  • 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">Angular</div>
    <div v-else-if="n===2">React</div>
    <div v-else-if="n===3">Vue</div>
    <div v-else>ming</div>
    
    <!-- v-if 可配合 template 使用达到对一个组控制的效果 -->
    <template v-if="n===1">
    	<div>Angular</div>
        <div>React</div>
        <div>Vue</div>
    </template>
    

14. v-for (列表渲染)

<body> 
    <div id="app">
        <h2>人员列表:</h2>
        <ul>
            <li v-for="(item, index) in persons" :key="item.id">
                {{item.id}}-{{item.name}}-{{item.age}}
                <input/>
            </li>
        </ul>
        
        <button @click.once="addPerson">添加一个老刘</button>
    </div>

    <script lang="ts">
        const vm = new Vue({
            el: '#app',
            data: {
                persons:[
                    {id:"001", name:"张三", age:18},
                    {id:"002", name:"李四", age:19},
                    {id:"003", name:"王五", age:20},
                ]
            },
            methods: {
                addPerson() {
                    let obj = {id: "004", name: "老刘", age: 21}
                    this.persons.unshift(obj)
                }
            }
        })

    </script>
</body>

key 值得作用:

image-20230524151841163

15. 列表过滤和排序

<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>

16. set(object, key, value) 添加响应式属性

向响应式对象中添加一个 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>

17. vue 监测数据总结

  1. vue 会监视 data 所有层次的数据

  2. 监测对象:
    通过 settter 实现监视,且要在 new vue 时就传入要监测的数据
    (1)对象后追加的属性,vue 默认不做响应式处理
    (2)如需给后添加的属性做响应式,以下 API
    Vue.set(target, propertyName/index, value)
    Vue.set(target, propertyName/index, value)

  3. 监测数组:
    (1) 调用原生对应的方法对数组更新(push, pop, unshift, shift, splice, sort, reverse)
    (2) 重新解析魔板,更新页面
    错误:this.student.friends[0] = {…}
    正确:this.student.friends[0].name = “”

18. 收集表单数据示例

<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>

19. vue 内部指令

v-text:向其所在的节点中渲染文本内容,不支持标签文本解析
v-html:向其所在的节点中渲染文本内容,支持标签文本解析
v-cloak:没有值,vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性,配合 css 选择器使用
v-once:在初次动态渲染后,就视为静态内容(没有响应式)
v-pre:跳过所在节点的编译过程(可利用它跳过没有使用指令语法,插值语法的节点,加快编译)

20. 生命周期

img

21. 非单文件组件

命名规则:
错误:myCom: myCom
正确:‘myCom’: myCom

<body> 
    <div id="app">
        <school></school>
        </br>
        <student></student>
    </div>

    <script lang="ts">
        const school = {
            template:`
                <div>
                    <h2>学校名称:{{name}}</h2>
                    <h2>学校地址:{{address}}</h2>
                </div>
            `,

            data() {
                return {
                    name: "HUFE",
                    address: "长沙",
                }
            },
        }

        const student = {
            template:`
                <div>
                    <h2>学生名称:{{name}}</h2>
                    <h2>学生年龄:{{age}}</h2>
                </div>
            `,

            data() {
                return {
                    name: "ming",
                    age: 18,
                }
            },
        }
        
        const vm = new Vue({
            el: '#app',

            data: {
              
            },
            methods: {

            },
            components: {
                school,	// 简写 = school:school
                student:student,
            },
        })
    </script>
</body>

22. vm 与 vc

  1. vm
    • Vue 实例
    • 通过 el 配置项决定为哪个容器服务
    • data 配置项可写成对象或函数
    • this 指向 vm
  2. vc
    • VueComponent 实例
    • 没有 el 配置项,可复用
    • data 配置项只能写成函数
    • this 指向 vc
  3. VueComponent.protptype.[[Prototype]]=== Vue.prototypr

23. 单文件组件(.vue)

脚手架下载: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>

24. ref 属性

  1. 用来给元素或子组件注册引用信息(id 的替代者)

  2. 应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc)

  3. 使用方式:

    <!-- 打标识 -->
    <h1 ref="xxx"></h1><School ref="xxx"></School>
    <!-- 获取 -->
    this.$refs.xxx
    

25. props 属性(父传子)

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+1</button>
    </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>	<!-- 使用 : 进行绑定 -->

26. mixin(混合)

提取 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>

27. scoped(局部样式)

<!-- 局部的样式,只在该.vue文件中使用 -->
<style scoped>
</style>

28. less

[使用手册](Less 快速入门 | Less.js 中文文档 - Less 中文网 (bootcss.com))

[安装]((22条消息) Vue 安装 Less(CSS 预处理器)_vue中如何安装less_卡尔特斯的博客-CSDN博客)

<style lang="less"></style>

29. 路由

安装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">Main</router-link><br>
    <router-link to="/login">Login</router-link><br>
    <router-link to="/register">Register</router-link><br>
    <router-view></router-view>
  </div>
</template>

30. 浏览器本地存储

  1. localStorage

    在 Application -> Local storage 中查看
    在清除浏览器缓存时会清空

    saveData() {
     localStorage.setItem("msg", "666")
     localStorage.setItem("person", JSON.stringify(this.p))
    },
    removeData() {  // 清除某个缓存
     localStorage.removeItem("msg")
    },
    clearData() { // 清除所有缓存
     localStorage.clear()
    }
    
  2. sessionStorage

    在 Application -> Session storage 中查看
    关闭浏览器清空缓存
    Api 同上,localStorage -> sessionStorage

31. $emit $on 组件自定义事件(子传父)

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

  1. 父组件可以使用 props 把数据传给子组件
  2. 子组件可以使用 $emit,让父组件监听到自定义事件
  1. App.vue

    <template>
      <div id="app">
        <h1>{{ msg }}</h1>
        <School :getSchoolName="getSchoolName"></School>
        <Student @stuName="getStudentName"></Student>
        <Student ref="student"></Student>
      </div>
    </template>
    
    <script>
    import Main from './components/Main.vue';
    import Student from './components/Student.vue';
    import School from './components/School.vue';
    
    export default {
      name: 'App',
      data() {
        return {
          msg: "你好啊",
        }
      },
      methods: {
        getSchoolName(name) {
            console.log("App 收到了学校名:", name)
        },
        getStudentName(name) {
          console.log("App 收到了学生名:", name)
        },
      },
      components:{Student, School},
      mounted() {
        this.$refs.student.$on('stuName', this.getStudentName)
        // 只执行一次
        // this.$refs.student.$once('stuName', this.getStudentName)
      }
    }
    </script>
    
  2. 通过父组件给子组件传递函数类型的 props 实现:子给父传数据:

    <template>
        <div class="school">
            <h2>学校名:{{ name }}</h2>
            <h2>学校地址:{{ address }}</h2>
            <button @click="sendSchoolName()">把学校名给App</button>
        </div>
    </template>
    
    <script>
        export default {
            name: 'school',
            props: ['getSchoolName'],
            data() {
                return {
                    name: 'HUFE',
                    address: "changsha"
                }
            },
            methods:{
                sendSchoolName() {
                    this.getSchoolName(this.name)
                }
            }
        }
    </script>
    
  3. 通过父组件给子组件绑定一个自定义事件实现:子给父传数据:

    <template>
      <div id="app">
        <h1>{{ msg }}</h1>
        <School :getSchoolName="getSchoolName"></School>
        <!-- 写法一 -->
        <Student @stuName="getStudentName" @click.native="stuClick"></Student>
        <!-- 写法二 -->
        <Student ref="student"></Student>
      </div>
    </template>
    
    <script>
    import Main from './components/Main.vue';
    import Student from './components/Student.vue';
    import School from './components/School.vue';
    
    export default {
      name: 'App',
      data() {
        return {
          msg: "你好啊",
        }
      },
      methods: {
        getSchoolName(name) {
            console.log("App 收到了学校名:", name)
        },
        getStudentName(name) {
          console.log("App 收到了学生名:", name)
        },
        stuClick() {
          alert("stuClick")
        }
      },
      components:{Student, School},
      mounted() {
        this.$refs.student.$on('stuName', this.getStudentName)
        // 只执行一次
        // this.$refs.student.$once('stuName', this.getStudentName)
      }
    }
    </script>
    

32. nextTick()

下一次 DOM 更新结束后执行器指定回调

this.$nextTick(function(){
 this.$refs.inputTitle.focus()
})

33. 插槽

  1. 默认插槽

    <template>
        <div class="sch">
            <h2>ming</h2>
            <slot>默认值,组件使用者没传时显示</slot>
        </div>
    </template>
    

    使用:

    <template>
      <div class="app">
        <Student>
          <img src="./assets/4.png" alt="">
        </Student>
      </div>
    </template>
    

Vue 3

注意事项

导入 .vue 组件

import Child from './components/Child.vue' 	// 不需要带 {}

0. 创建 vue3 工程

  1. 通过 cli 创建 vue3 js 工程

    1. 查看 cli 版本,版本需在 4.5.0 以上
      vue -V
      npm install -g @vue/cli (默认安装最新版本cli)
    2. 创建工程,选择 vue 版本
      vue create vue3_test (工程名)
  2. 通过 cli 创建 vue3 ts 工程

    1. 确认版本:
      node(14.x 以上):node -v 若版本不够,去 node 官网下载
      vue-cli(4.x 以上):vue -V 若版本不够,npm install -g @vue/cli
    2. 创建项目
      vue create vue3ts_demo(项目名)
      选择第三项,自定义配置(光标移动到对应处,按空格选择)
      在这里插入图片描述
  3. 通过 vite 创建 vue3 ts 工程

    npm create vite@latest my-vue-app --template vue-ts
    

    创建工程后使用:npm -i 安装模块

1. setup 函数

<template>
  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <button @click="sayHello">SayHello</button>
</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">SayHello</button>
</template>

<script setup>
    let name = "ming"
    let age = 18

    function sayHello() {
      alert(`Hello, I am ${name},my age is ${age}`)
    }
</script>

2. ref 函数(为数据做响应式)

<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>

3. reactive 函数(处理对象响应式)

<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>

4. 新增/删除属性

<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>

5. computed 计算属性

<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>

6. watch 数据监视

<template>
  <h2>num:{{ num }}</h2>
  <button @click="num++">点我num+1</button><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>

7. watchEffect

/* 
    1.初始就会执行一次
    2.监视函数体中使用到某个属性,若该属性改变了就会执行一次
  */
  watchEffect(() => {
    console.log("watchEffect 调用了")
    let x = num.value
    let y = person.job.salary
  })

8. 生命周期

图:官网查看

beforeCreate == setup()
beforeCreate == setup()

9. hook (复用代码)

创建一个 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>

10. toRef 和 toRefs

  • 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>

11. shallowReactive

只处理对象最外层属性的响应式(浅响应式)

12. readonly 和 shallowReadOnly

  • readonly: 让一个响应式数据变为只读的(深只读)。
  • shallowReadOnly: 让一个响应式数据变为只读的(浅只读)

13. toRaw 和 markRaw

  • toRaw : 将一个 reactive 生成的响应式对象转为普通对象
  • markRaw: 标记一个对象,使其永远不会再成为响应式对象

14. provide 和 inject

作用:实现祖孙间通信

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXKRhQah-1689749017405)(C:\Users\cli08\AppData\Roaming\Typora\typora-user-images\image-20230530234850863.png)]

<!-- app -->
<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>

15.响应式数据判断

  • isRef,是否是由ref定义的响应式数据
  • isReactive,是否是由reactive定义的响应式数据
  • isReadonly,是否是由readonly定义的数据
  • isProxy,是否是由reactivereadonly定义的数据

16. Router (路由)

  1. 安装:npm install vue-router@4
  2. useRouter:对路由的控制,用来路由跳转
    useRoute:路由的信息,用来路由传参
  1. 使用示例

    单个页面(Login.vue 和 Main.vue):

    <template>
        <h2>我是Login组件</h2>
    </template>
    
    <script setup>
        
    </script>
    

    Game.vue

    <template>
        <div class="game">
            <h2>我是Game组件</h2>
            <router-link to="/game/game_1">Game_1</router-link><br>
            <router-link to="/game/game_2">Game_2</router-link><br>
            <router-link to="/game/game_3">Game_3</router-link><br>
            <router-view></router-view>
        </div>
    </template>
    
    <script setup lang="ts">
        
    </script>
        
    <style scoped>
        .game {
            background-color: pink;
            padding: 10px;
        }
    </style>
    

    Game_1.vue(Game_2.vue, Game_3.vue 类似)

    <template>
        <div class="game_1">
            <h2>我是Game_1组件</h2>
        </div>
    </template>
    
    <script setup lang="ts">
    </script>
    
    <style scoped>
        .game_1 {
            background-color: goldenrod;
        }
    </style>
    

    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

    <template>
      <router-link to="/main">Main</router-link><br>
      <router-link to="/login">Login</router-link><br>
      <router-link to="/register">Register</router-link><br>
      <router-view></router-view>
    </template>
    
    <script>
      export default {
        name: 'App',
      }
    </script>
    
  2. 路由传参

    • query

      <router-link :to="{
         path: '/main',
         query: {
         	p1: 'ming',
         	p2: 18
         }
      }">
          Main
      </router-link><br>
      
      <!-- 在对应组件上接收参数 -->
      <script setup lang="ts">
          import { useRouter, useRoute } from 'vue-router';
          const route = useRoute()
          console.log(route.query)
      </script>
      
    • param

      <router-link :to="{
            name: 'login',
            params: {
              p3: 'ming',
              p4: 18
            }
      }">Login</router-link><br>
      
      <!-- 在对应组件上接收参数 -->
      <script setup lang="ts">
          import { useRoute, useRouter } from 'vue-router';
          const route = useRoute()
          console.log(route.params)
      </script>
      
  3. 编程式路由导航

    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)	// 向后移动一条历史记录
    

17. pinia 状态管理器使用

  1. 安装 pinia :npm install pinia

  2. 修改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");
    
  3. src 下创建文件夹 store,用来存放共享数据

  1. 创建 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
        };
      });
    
  2. 使用

    <template>
      <img alt="Vue logo" src="./assets/4.png" />
      <h2>姓名:{{ student.name }}</h2>
      <h2>年龄:{{ student.age }}</h2>
      <h2>性别:{{ student.sex }}</h2>
      <h2>职位:{{ student.job.type }}</h2>
      <h2>薪水:{{ student.job.salary }}</h2>
      <button @click="addAge(1)">点我年龄+1</button>
    </template>
    
    <script setup lang="ts">
      import { ref, reactive } from "vue";
      import { useUsersStore } from "../src/store/user";
    
      const userStore = useUsersStore();
      const {student, addAge} = userStore
      
      console.log(userStore)
    </script>
    
    <style scoped>
    </style>
    
    

18. ref 获取 DOM 元素

<script setup lang="ts">
    const ctx = ref<HTMLDivElement>()
    onMounted(() => {
      console.log("hwm", ctx.value)
    })
</script>

<template>
	<div class="game-list" ref="ctx"></div>
</template>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/40544.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【java爬虫】使用selenium获取某宝联盟淘口令

上一篇文章我们已经介绍过使用selenium获取优惠券基本信息的方法 (15条消息) 【java爬虫】使用selenium爬取优惠券_haohulala的博客-CSDN博客 本文将在上一篇文章的基础上更进一步&#xff0c;获取每个优惠券的淘口令&#xff0c;毕竟我们只有复制淘口令才能在APP里面获取优惠…

基于ChatGPT和私有知识库搭建Quivr项目

准备工作 安装docker和docker-compose申请supabase账号 拉取Quivr代码 git clone https://github.com/StanGirard/Quivr.git 复制.XXXXX_env文件 cp .backend_env.example backend/.env cp .frontend_env.example frontend/.env 更新backend/.env和frontend/.env文件 ba…

【hadoop】部署hadoop全分布模式

hadoop全分布模式 全分布模式特点部署全分布模式准备工作正式配置hadoop-env.shhdfs-site.xmlcore-site.xmlmapred-site.xmlyarn-site.xmlslaves对NameNode进行格式化复制到另外两台虚拟机启动 对部署是否成功进行测试 全分布模式特点 真正的分布式环境&#xff0c;用于生产具…

java学习003

Java数组 Java 语言中提供的数组是用来存储固定大小的同类型元素&#xff0c;这一点和PHP语言的可变数组长度不同。 声明变量数组 首先必须声明数组变量&#xff0c;才能在程序中使用数组。下面是声明数组变量的语法&#xff1a; dataType[] arrayRefVar; // 首选的方法 或 …

2023-07-18力扣今日二题-太难了吧

链接&#xff1a; LCP 75. 传送卷轴 题意&#xff1a; 给一个正方形迷宫&#xff0c;主角是A&#xff0c;每次可以上下左右走一格子&#xff0c;有四种类型的格子&#xff1a;墙、初始位置、魔法水晶、空地 另一个人B&#xff0c;可以传送一次A&#xff0c;只能在空地传送&…

017 - STM32学习笔记 - SPI读写FLASH(二)-flash数据写入与读取

016 - STM32学习笔记 - SPI访问Flash&#xff08;二&#xff09; 上节内容学习了通过SPI读取FLASH的JEDEC_ID&#xff0c;在flash资料的指令表中&#xff0c;还看到有很多指令可以使用&#xff0c;这节继续学习使用其他指令&#xff0c;程序模板采用上节的模板。 为了方便起…

基于深度学习的高精度线路板瑕疵目标检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度线路板瑕疵目标检测系统可用于日常生活中来检测与定位线路板瑕疵目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的线路板瑕疵目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5…

计算机网络 day6 arp病毒 - ICMP协议 - ping命令 - Linux手工配置IP地址

目录 arp协议 arp病毒\欺骗 arp病毒的运行原理 arp病毒产生的后果&#xff1a; 解决方法&#xff1a; ICMP协议 ICMP用在哪里&#xff1f; ICMP协议数据的封装过程 ​编辑 为什么icmp协议封装好数据后&#xff0c;还要加一个ip包头&#xff0c;再使用ip协议再次进…

Docker 基础知识解析:容器与传统虚拟化对比:资源利用、启动时间、隔离性和部署效率

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

国赛线下开赛!全国智能车百度智慧交通创意组区域赛今日正式拉开帷幕!

“全国大学生智能汽车竞赛”是教育部倡导的大学生科技A类竞赛&#xff0c;中国高等教育学会将其列为含金量最高的大学生竞赛之一&#xff0c;为《全国普通高校大学生竞赛排行榜》榜单内赛事。飞桨共承办了百度完全模型组和百度智慧交通组两大赛道。全国大学生智能汽车竞赛百度智…

SpringBoot(七)Filter的使用

思考一个问题&#xff0c;服务端对于客户端的请求&#xff0c;真的应该照单全收吗&#xff1f;不是的。比如拿我们之前实现的用户注册功能来看&#xff0c;如果用户的昵称带了一些不友好的字母或汉字&#xff0c;你是给他过滤掉呢还是让他注册呢&#xff1f;毫无疑问&#xff0…

HTTP 请求走私漏洞(HTTP Request Smuggling)

一、什么是Http 请求走私漏洞&#xff1f; HTTP请求走私漏洞&#xff08;HTTP Request Smuggling&#xff09;是一种安全漏洞&#xff0c;利用了HTTP协议中请求和响应的解析和处理方式的不一致性。攻击者通过构造特定的恶意请求&#xff0c;以欺骗服务器和代理服务器&#xff0…

五、DQL-2.基本查询

一、数据准备 1、删除表employee&#xff1a; drop table employee; 2、创建表emp&#xff1a; 3、添加数据&#xff1a; 4、查看表数据&#xff1a; 【代码】 -- 查询数据--------------------------------------------------------- drop table emp;-- 数据准备-----------…

Ubuntu 的安装及其设置

文章目录 安装 Ubuntu屏幕分辨率设置修改软件源服务器锁屏时间设置设置 dash跨系统拖拽复制文件的设置 安装 Ubuntu 首先安装 VMware 虚拟机&#xff0c;虚拟机的安装比较简单&#xff0c;一步步点击Next即可完成安装。 安装完成后启动虚拟机&#xff0c;点击创建新的虚拟机。…

个人博客系统(二)

该博客系统共有八个页面,即注册页面、登录页面、添加文章页面、修改文章页面、我的博客列表页面、主页、查看文章详情页面、个人中心页面。 1 注册页面 该页面如图所示: 首先,要先判断注册的用户名、密码、确认密码以及验证码是否为空,若有一个为空,点击提交,则会提醒 …

“探索图像处理的奥秘:使用Python和OpenCV进行图像和视频处理“

1、上传图片移除背景后下载。在线抠图软件_图片去除背景 | remove.bg – remove.bg 2、对下载的图片放大2倍。ClipDrop - Image upscaler 3、对放大后的下载照片进行编辑。 4、使用deepfacelive进行换脸。 1&#xff09;将第三步的照片复制到指定文件夹。C:\myApp\deepfakeliv…

MFC第十六天 CFileDialog、CEdit简介、(线程)进程的启动,以及Notepad的开发(托盘技术-->菜单功能)

文章目录 CCommonDialogCFileDialogCEdit托盘技术进程的启动附录1:启动线程方式附录2:MFC对话框的退出过程 CCommonDialog 通用对话框 CCommonDialog 这些对话框类封装 Windows 公共对话框。 它们提供了易于使用的复杂对话框实现。 CFileDialog 提供用于打开或保存文件的标准对…

【前端】自制密码展示隐藏按钮

效果 一、前期准备 使用的图片是iconfront上拿的svg代码环境是Vue2 Element 二、创建组件 showPasswordAndclose <template><span class"show-password-container"><span v-if"chooseType CLOSE" click"changeType"><…

手机图片怎么转pdf格式?这几个图片转换方式了解一下

手机图片怎么转pdf格式&#xff1f;将图片转换为PDF的应用场景非常广泛。例如&#xff0c;你可以将多张照片转换为PDF&#xff0c;然后将其作为一本电子相册保存。你也可以将多张图片转换为PDF&#xff0c;然后将其作为一份报告或文档的附件发送给他人。此外&#xff0c;许多人…

数据结构双向链表,实现增删改查

一、双向链表的描述 在单链表中&#xff0c;查找直接后继结点的执行时间为O(1)&#xff0c;而查找直接前驱的执行时间为O(n)。为克服单链表这种单向性的缺点&#xff0c;可以用双向链表。 在双向链表的结点中有两个指针域&#xff0c;一个指向直接后继&#xff0c;另一个指向直…
最新文章