Ansible 变量与加密文件全解析:从基础定义到安全实践

Ansible 变量与加密文件全解析:从基础定义到安全实践

一、变量命名规则

  • 变量名只能包含 字母、数字、下划线
  • 必须以 字母开头(不能以数字或下划线开头)
  • 区分大小写(my_varMy_Var 是不同变量)
  • 避免使用 Ansible 预定义的特殊变量名(如 inventory_hostnamegroups 等)

二、变量优先级(受版本影响可能会有略微不同)

1. Global 范围(最高优先级)

作用于整个 Ansible 执行过程 ,覆盖所有 Play 和主机,通常用于 "全局强制配置"。

主要来源:

  • 命令行变量 :通过 -e/--extra-vars 传递,是优先级最高的变量(除非特殊配置),常用于临时覆盖其他变量。

    复制代码
    [student@master ansible]$ ansible-playbook abc.yml -e "env=prod app_port=8080"
  • Ansible 配置文件变量 :在 ansible.cfg 中定义的变量(如 remote_userinventory),属于全局默认配置。

  • 环境变量 :系统环境变量中以 ANSIBLE_ 开头的变量(如 ANSIBLE_REMOTE_USER),会覆盖 ansible.cfg 中的对应配置。

2. Play 范围(中优先级)

作用于单个 Play 内的所有主机,仅在当前 Play 生效,常用于 "Play 级别的统一配置"。

  • set_fact定义变量:也是将值赋值给变量。

  • Play 的 vars 块:在 Play 中直接定义的变量,优先级高于 Host 范围变量。

    示例:

    yaml 复制代码
    - name: aaaaaa
      hosts: node1
      vars:  # Play 级变量
        - aaa: 11
        - bbb: 22
      tasks:
        - name: abcd
          debug:
            var: aaa,bbb
    [student@master ansible]$ ansible-playbook aaa.yml 
    ok: [node1] => {
        "aaa,bbb": "(11, 22)"
    }
  • Play 的 vars_files 块 :通过外部 YAML/JSON 文件引入的变量(如 vars/prod.yml),与 vars 块优先级相同(按定义顺序,后定义的覆盖先定义的)。

    yaml 复制代码
    [student@master ansible]$ vim bbb.yml   
    aaa: 123
    bbb: 321 
    - name: aaa
      hosts: node5
      vars_files: /home/student/ansible/bbb.yml
      tasks:
        - name: abcd
          debug:
            var: aaa,bbb
    [student@master ansible]$ ansible-playbook aaa.yml 
    ok: [node5] => {
        "aaa,bbb": "(123, 321)"
    }
  • Role 的 vars 目录 :Role 内部 vars/main.yml 中定义的变量,优先级高于 Role 的 defaults,且属于 Play 范围(因为 Role 依附于 Play 执行)。

  • Role 的 defaults 目录 :Role 内部 defaults/main.yml 中定义的变量,是 Role 的 "默认值",优先级低于 Play 的 vars 和 Host 范围变量(注意:这是 Play 范围内的 "次优先级",容易混淆)。

3. Host 范围(最低优先级)

作用于特定主机或主机组 ,仅对目标主机生效,常用于 "主机个性化配置"。

主要来源:

  • Inventory 主机变量 :直接在 Inventory 文件中为单个主机定义的变量(如 web1 ansible_host=192.168.1.10 app_port=80)。
  • Inventory 组变量 :为 Inventory 中的主机组定义的变量(如在 group_vars/webservers.yml 中定义 web_root=/var/www/html),组内所有主机共享。
  • Facts 变量 :Ansible 自动收集的主机信息(如 ansible_os_familyansible_memtotal_mb),变量名以 ansible_ 开头。默认情况下,Facts 变量不能被普通变量覆盖 (需通过 gather_facts: no 关闭,或修改 ansible.cfg 中的 allow_world_readable_facts 配置)。
  • Register 变量 :通过 register 关键字捕获任务执行结果的变量(如捕获 command 模块的输出),仅在当前 Play 内的目标主机生效,属于 "临时 Host 变量"。
    示例:

注册和定义变量的各种方式

ansible中定义变量的方式有很多种,大致有:

(1) 将模块的执⾏结果注册为变量

(2) 直接定义字典类型的变量;

(3) role中⽂件内定义变量;

(4) 命令⾏传递变量;

(5) 借助with_items迭代将多个task的结果赋值给⼀个变量;

(6) inventory中的主机或主机组变量;

(7) 内置变量。

(8)事实变量

(1) 将模块的执⾏结果注册为变量

在 Ansible 中,register 是一个非常实用的选项,它能将当前任务(task)的执行结果完整捕获并赋值给一个自定义变量。这个变量可以包含任务的输出内容、状态信息、返回码等细节,供后续任务进行判断、提取数据或做进一步处理。

核心作用
  • 保存任务执行的详细结果(成功 / 失败状态、输出内容、返回码等)
  • 实现 "基于前序任务结果的条件执行"
  • 提取任务输出中的关键信息(如命令返回值、文件状态等)

基本语法

yaml 复制代码
- name: 任务名称
  模块名:
    模块参数
  register: 自定义变量名  # 将结果赋值给该变量

例:

bash 复制代码
---
- name: aaa
  hosts: node1
  tasks:
    - name: cat file
      shell:
        cmd: sudo cat /tmp/1aa
      register: abc

    - name: creste debug
      debug:
        var: abc
        
        
[student@master ansible]$ ansible-playbook aaa.yml 

PLAY [aaa] *********************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [node1]

TASK [cat file] ****************************************************************************
changed: [node1]

TASK [creste debug] ************************************************************************
ok: [node1] => {
    "abc": {
        "changed": true,
        "cmd": "sudo cat /tmp/1aa",
        "delta": "0:00:00.014112",
        "end": "2025-09-01 20:19:39.712909",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2025-09-01 20:19:39.698797",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "aaaaaaaa",
        "stdout_lines": [
            "aaaaaaaa"
        ]
    }
}

PLAY RECAP *********************************************************************************
node1                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

如果只想要任务执行的结果

将var后面的值改成abc.stdout

bash 复制代码
---
- name: aaa
  hosts: node1
  tasks:
    - name: cat file
      shell:
        cmd: sudo cat /tmp/1aa
      register: abc

    - name: creste debug
      debug:
        var: abc.stdout
        
[student@master ansible]$ ansible-playbook aaa.yml         
TASK [creste debug] ************************************************************************
ok: [node1] => {
    "abc.stdout": "aaaaaaaa"
}
(2) 直接定义字典类型的变量;

在 Ansible 中,字典(dictionary)类型变量用于存储键值对(key-value)形式的数据,非常适合组织关联信息(如配置参数、多属性对象等)。直接定义字典变量的方式灵活,可在 Playbook、变量文件、set_fact等场景中使用,语法遵循 YAML 格式。

一、基本语法(YAML 字典格式)

Ansible 中字典的基本格式为:

键值对

yaml 复制代码
字典名:
  键1: 值1
  键2: 值2
  键3: 值3  # 值可以是字符串、数字、列表、甚至嵌套字典

键(key)通常不需要引号(特殊字符除外),值(value)支持多种类型(字符串、数字、列表、布尔值、嵌套字典等)。

实列在上面Play 范围(中优先级)中有写

(3) role中⽂件内定义变量;

未学之后补

(4) 命令⾏传递变量;

在 Ansible 中,通过命令行传递变量 是一种灵活的方式,常用于临时覆盖配置、动态指定参数(如环境标识、版本号等)。命令行传递的变量优先级最高,会覆盖 Playbook、变量文件、Inventory 等其他位置定义的同名变量,非常适合临时调整任务行为。

核心语法

通过 -e--extra-vars 选项传递变量,基本格式:

bash 复制代码
ansible-playbook 剧本名.yml -e "变量名=值"  # 单个变量
ansible-playbook 剧本名.yml -e "变量1=值1 变量2=值2"  # 多个变量(空格分隔)

列:

yaml 复制代码
---
- name: aaa
  hosts: node1
  tasks:
    - name: debug
      debug:
        msg: aaa={{ccc}} bbb={{ddd}}

[student@master ansible]$ ansible-playbook -e "ccc=111 ddd=222" aaa.yml       

ok: [node1] => {
    "msg": "aaa=111 bbb=222"
}

(5) 借助with_items迭代将多个task的结果赋值给⼀个变量;

在 Ansible 中,当使用 with_items(或较新的 loop)进行迭代时,任务会对列表中的每个项执行一次。此时,通过 register 注册的变量会自动包含一个 results 列表,存储每个迭代项的执行结果 。我们可以通过这个 results 列表,将多个迭代任务的结果汇总到一个变量中,实现 "将多个 task 结果赋值给一个变量" 的效果。

核心原理
  • 当任务使用 with_items 循环时,register 注册的变量会生成一个 results 属性(列表类型)。
  • results 列表中的每个元素对应一次迭代的结果,包含当前迭代项(item)和该次任务的详细输出(如 stdoutrcstat 等)。
  • 可通过遍历 results 列表,提取每个迭代的结果,实现对多个任务结果的集中处理。

例:

bash 复制代码
---
- name: aaa
 hosts: node1
 tasks:
   - name: debug
     shell:
       cmd: echo {{ item }}
     with_items:
       - aaaa
       - bbbb
       - cccc
     register: cy

   - name: look cy
     debug:
       var: cy.results[{{ item }}].stdout
     with_items:
       - 0
       - 1
       - 2

[student@master ansible]$ ansible-playbook aaa.yml 

*******************************************************************************
changed: [node1] => (item=aaaa)
changed: [node1] => (item=bbbb)
changed: [node1] => (item=cccc)

TASK [look cy] *****************************************************************************
ok: [node1] => (item=0) => {
   "ansible_loop_var": "item",
   "cy.results[0].stdout": "aaaa",
   "item": 0
}
ok: [node1] => (item=1) => {
   "ansible_loop_var": "item",
   "cy.results[1].stdout": "bbbb",
   "item": 1
}
ok: [node1] => (item=2) => {
   "ansible_loop_var": "item",
   "cy.results[2].stdout": "cccc",
   "item": 2
}

(6) inventory中的主机或主机组变量;

在 Ansible 中,inventory( inventory 文件或动态 inventory )不仅用于定义主机和主机组,还可以直接为主机主机组定义变量。这些变量可以在 Playbook、模板、模块中直接引用,用于定制针对特定主机或主机组的操作。

1. 主机变量(Host Variables)

主机变量是针对单个主机 定义的变量,仅对该主机生效。

通常用于描述主机的个性化属性(如 IP、端口、特定配置等)。

定义方式(在 inventory 文件中):
ini 复制代码
node1 aaa=1111
node2 aaa=2222
node3 aaa=3333
node4
node5

在剧本中

yaml 复制代码
---
- name: aaaaaa
  hosts: node1,node2,node3
  tasks:
    - name: abcd
      debug:
        var: aaa

运行结果

bash 复制代码
[student@master ansible]$ ansible-playbook bbb.yml 

PLAY [aaaaaa] ******************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [node1]
ok: [node3]
ok: [node2]

TASK [abcd] ********************************************************************************
ok: [node1] => {
    "aaa": 1111
}
ok: [node2] => {
    "aaa": 2222
}
ok: [node3] => {
    "aaa": 3333
}

也可用组的形式

inventory

ini 复制代码
[t1]
node1
node2


[t2]
node3
node4


[t3]
node5


[t1:vars]
aaa=123456

[t2:vars]
aaa=654321

[t3:vars]
aaa=abcdef

剧本

yaml 复制代码
---
- name: aaaaaa
  hosts: all
  tasks:
    - name: abcd
      debug:
        var: aaa

运行结果

bash 复制代码
[student@master ansible]$ ansible-playbook bbb.yml 

ok: [node1] => {
    "aaa": 123456
}
ok: [node2] => {
    "aaa": 123456
}
ok: [node3] => {
    "aaa": 654321
}
ok: [node4] => {
    "aaa": 654321
}
ok: [node5] => {
    "aaa": "abcdef"
}

创建host和组的专属存放变量文件的目录

  1. host_vars 目录(主机专属变量)
    • 路径:/etc/ansible/host_vars/(全局)或 Playbook 所在目录下的 host_vars/(项目内)。
    • 文件名与主机名一致,用于定义特定主机的变量。
  2. group_vars 目录(组专属变量)
    • 路径:/etc/ansible/group_vars/(全局)或 Playbook 所在目录下的 group_vars/(项目内)。
    • 文件名与组名一致,用于定义特定组内所有主机共享的变量。
bash 复制代码
[student@master ansible]$ mkdir host_vars
[student@master ansible]$ mkdir group_vars

[student@master ansible]$ vim host_vars/node1
aaa: 12345678

[student@master ansible]$ vim host_vars/node1.yml 
aaa: abcdefg

[student@master ansible]$ vim group_vars/t1
bbb: 1234

剧本

yaml 复制代码
---
- name: aaaaaa
  hosts: node1
  tasks:
    - name: abcd
      debug:
        var: aaa,bbb

运行效果

bash 复制代码
[student@master ansible]$ ansible-playbook bbb.yml 

PLAY [aaaaaa] ******************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [node1]

TASK [abcd] ********************************************************************************
ok: [node1] => {
    "aaa,bbb": "(12345678, 1234)"
}

删除/etc/ansible/host_vars/node1 保留/etc/ansible/host_vars/node1.yml,再次执行playbook

bash 复制代码
[student@master ansible]$ ansible-playbook bbb.yml 

PLAY [aaaaaa] ******************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [node1]

TASK [abcd] ********************************************************************************
ok: [node1] => {
    "aaa,bbb": "('abcdefg', 1234)"
}

(7)事实变量与内置变量

1. 事实变量(Facts Variables)
  • 定义 :Ansible 在执行 Playbook 时,通过setup模块自动从目标主机收集的系统 / 环境信息,是 "关于目标主机的动态事实"。
  • 本质:是目标主机的 "属性快照",内容完全依赖目标主机的实际状态(如操作系统版本、IP 地址、硬件配置等),不同主机的事实变量可能完全不同。
  • 特点:默认自动收集(可通过gather_facts: no关闭),内容动态、主机相关。
2. 内置变量(Built-in Variables)
  • 定义 :Ansible 框架自带的、不依赖目标主机的元数据变量,用于获取 Ansible 运行时信息、Inventory 配置信息或 Play/Task 上下文。
  • 本质:是 "关于 Ansible 自身或执行上下文的固定 / 半固定信息",不依赖目标主机,仅与 Ansible 环境、Inventory 配置或当前 Play 逻辑相关。
  • 特点:无需主动收集,Playbook 中可直接引用;内容静态(如 Ansible 版本)或基于配置(如 Inventory 分组),与目标主机无关。
1. 常用事实变量(Facts)

通过ansible node1 -m setup 可以查询node1主机所有的事实变量

  • ansible_hostname:目标主机的主机名(如web-server-01)。
  • ansible_os_family:目标主机的操作系统家族(如RedHatDebianWindows),常用于条件判断(例:RedHat 系装yum包,Debian 系装apt包)。
  • ansible_enp1s0.ipv4.address:目标主机网卡enp1s0的 IPv4 地址(如192.168.122.10)。
  • ansible_default_ipv4.address:目标主机的默认网卡ipv4地址
  • ansible_memtotal_mb:目标主机的总内存(单位:MB,如16384)。
  • ansible_pkg_mgr:目标主机默认的包管理器(如dnfaptpip)。
  • ansible_fqdn: 目标主机完全合格域名(FQDN)
  • ansible_bios_version
  • ansible_devices.vda.size: vda硬盘大小
  • ansible_devices.vdb.size: vdb硬盘大小
  • ansible_lvm.vgs: 逻辑卷中卷组
2. 常用内置变量(Built-in)
  • ansible_version:当前 Ansible 的版本信息(字典类型,如ansible_version.full2.16.3),常用于确保 Playbook 兼容特定版本。

  • inventory_hostname:目标主机在 Inventory 文件中定义的 "主机名 / 别名"(如 Inventory 中写web01 ansible_host=192.168.1.100,则inventory_hostnameweb01)。

  • play_hosts:当前 Play 的目标主机列表(列表类型,如["web01", "web02"]),常用于批量操作(例:获取所有目标主机 IP)。

  • ansible_play_name:当前 Play 的名称(如 Play 定义name: 部署Web服务,则此变量值为部署Web服务)。

  • groups

  • group_names:当前主机所属的 Inventory 分组列表(如["web_servers", "prod"]),常用于按分组执行任务。

  • groups.all 所有清单主机

  • groups.ungrouped:未分组的主机

  • inventory_dir:Inventory 文件所在的目录路径(如/etc/ansible/inventory)。

set_fact定义变量

在 Ansible 中,set_fact 是用于主动定义自定义事实变量(custom facts) 的模块。这些变量会被添加到主机的事实(facts)集合中,可在后续任务、甚至跨 Play 中像其他内置 facts(如 ansible_hostname)一样直接引用。set_fact 更接近 "动态变量赋值" 的逻辑,尤其适合基于现有变量(如 facts、register 结果、其他变量)构造新变量。

yaml 复制代码
---
- name: aaa
  hosts: all
  tasks:
    - name: set_fact     #将目标主机的域名变量和ip地址变量写成1一个变量
      set_fact:
        dns_and_ip: "{{ ansible_fqdn }}:{{ ansible_enp1s0.ipv4.address }} "

    - name: debug1
      debug:
        msg: "{{ ansible_hostname }} is {{ dns_and_ip }}  "


[student@master ansible]$ ansible-playbook aaa.yml 
ok: [node1] => {
    "msg": "node1 is node1.example.com:192.168.122.10   "
}
ok: [node2] => {
    "msg": "node2 is node2.example.com:192.168.122.20   "
}
ok: [node3] => {
    "msg": "node3 is node3.example.com:192.168.122.30   "
}
ok: [node4] => {
    "msg": "node4 is node4.example.com:192.168.122.40   "
}
ok: [node5] => {
    "msg": "node5 is node5.example.com:192.168.122.50   "
}

ansible_vault使用详解

Ansible Vault 是 Ansible 自带的敏感信息加密工具,用于加密包含密码、API 密钥、数据库凭证等敏感数据的文件(如变量文件、inventory 清单、playbook 片段等),防止敏感信息以明文形式存储在代码或配置文件中。

ansible_vault核心操作命令

创建加密的文件:

要创建新的加密文件,使用命令

bash 复制代码
ansible-vault create [选项] 文件名

常用选项

  • --vault-id 标识@密码文件`:指定加密密码(多密码场景)。
  • --ask-vault-pass:手动输入密码(默认方式)。

bash 复制代码
[student@master ansible]$ ansible-vault create ccc.yml 
New Vault password:   #输入密码
Confirm New Vault password:   #再次输入密码

使用vim和cat查看文件就会显示加密信息

bash 复制代码
[student@master ansible]$ cat ccc.yml 
$ANSIBLE_VAULT;1.1;AES256
36363464306637663362313261363430636565626364663233663030396136343862386161323565
6562643230383161623263663235383239613137353736650a396166656163333763373739633561
.......


[student@master ansible]$ vim ccc.yml 
$ANSIBLE_VAULT;1.1;AES256
36363464306637663362313261363430636565626364663233663030396136343862386161323565
6562643230383161623263663235383239613137353736650a396166656163333763373739633561
......

零时查看加密文件:

查看加密信息就要使用命令

bash 复制代码
ansible-vault view [选项] 文件名

yaml 复制代码
[student@master ansible]$ ansible-vault view ccc.yml 
Vault password: #输入密码
--- 
- name: ccc
  hosts: node1
  tasks: 
    - name: debug1
      debug: 
        msg: echo 123456 

输入密码后即可查看内容

修改加密文件

修改使用命令

bash 复制代码
ansible-vault edit [选项] 文件名

例:

yaml 复制代码
[student@master ansible]$ ansible-vault edit ccc.yml 
Vault password:  #输入密码
---
- name: ccc
  hosts: node1
  tasks:
    - name: debug1
      debug:
        msg: echo 123456

解密加密文件

解密的命令

bash 复制代码
ansible-vault decrypt [选项] 文件名

常用选项

  • --output 新文件名:解密到新文件(保留原加密文件)。

bash 复制代码
[student@master ansible]$ ansible-vault decrypt ccc.yml 
Vault password: 
Decryption successful

之后就可以直接查看和修改ccc.yml

bash 复制代码
[student@master ansible]$ cat ccc.yml 
--- 
- name: ccc
  hosts: node1
  tasks: 
    - name: debug1
      debug: 
        msg: echo 123456 

对已有的明文文件加密:

对文件加密使用

bash 复制代码
ansible-vault encrypt [选项] 文件名1 文件名2 ...

bash 复制代码
[student@master ansible]$ ansible-vault encrypt ccc.yml 
New Vault password: 
Confirm New Vault password: 
Encryption successful

再次查看就会发现

bash 复制代码
[student@master ansible]$ cat ccc.yml 
$ANSIBLE_VAULT;1.1;AES256
61373961663061356430643531613730623135373936663732353335393638643739623635613332
3530646333376437326330323532616330643131376234650a346362613663656564313635316466
..........

重设密码:

重设密码使用命令:

bash 复制代码
ansible-vault rekey [选项] 文件名1 文件名2 ...

bash 复制代码
[student@master ansible]$ ansible-vault rekey ccc.yml 
Vault password:  #旧密码
New Vault password:  #新密码
Confirm New Vault password: #再出输入新密码 
Rekey successful

ansible-vault encrypt_string

执行加密剧本

如果直接执行加密剧本

bash 复制代码
[student@master ansible]$ ansible-playbook ccc.yml 
ERROR! Attempting to decrypt but no vault secrets found

这时候就需要命令

bash 复制代码
ansible-playbook 文件名 --vault-id @prompt
或者
ansible-playbook 文件名 --ask-vault-pass

bash 复制代码
[student@master ansible]$ ansible-playbook ccc.yml --ask-vault-pass
Vault password:  #输入密码

PLAY [ccc] *********************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [node1]

TASK [debug1] ******************************************************************************
ok: [node1] => {
    "msg": "echo 123456"
}

用装有密码的文件输入密码

加上选项 --vault-id 存放密码的文件

bash 复制代码
#创建存放密码的文件
[student@master ansible]$ echo 3edc4rfv > pass
#将文件设置为仅自己可读写提升安全性
[student@master ansible]$ chmod 600 pass 
#运行加密脚本
[student@master ansible]$ ansible-playbook ccc.yml --vault-id pass

PLAY [ccc] ********************************************************************************

TASK [Gathering Facts] ********************************************************************
ok: [node1]

TASK [debug1] *****************************************************************************
ok: [node1] => {
    "msg": "echo 123456"
}

执行使用了加密文件的剧本

创建一个加密的存放变量的文件

bash 复制代码
[student@master ansible]$ ansible-vault create var.yml
New Vault password: 
Confirm New Vault password:

创建密码文件

bash 复制代码
[student@master ansible]$ echo 123456 >  varpass
[student@master ansible]$ chmod 600 varpass 

编写剧本

yaml 复制代码
---
- name: ccc
  hosts: node1
  vars_files: /home/student/ansible/var.yml
  tasks:
    - name: debug1
      debug:
        msg: "{{aaa,bbb}}"

如果直接运行就会

bash 复制代码
[student@master ansible]$ ansible-playbook ccc.yml 
ERROR! Attempting to decrypt but no vault secrets found

需要带上密码文件的地址

bash 复制代码
[student@master ansible]$ ansible-playbook ccc.yml --vault-id varpass

PLAY [ccc] ********************************************************************************

TASK [Gathering Facts] ********************************************************************
ok: [node1]

TASK [debug1] *****************************************************************************
ok: [node1] => {
    "msg": "(112233, 332211)"
}
相关推荐
共享ui设计和前端开发2 小时前
UI前端大数据可视化实战策略:如何设计符合用户认知的数据可视化界面?
前端·ui·信息可视化
2503_928411562 小时前
9.2 BOM对象
前端·javascript
whysqwhw3 小时前
JavaScript 动态代理全面指南
前端
云盾安全防护3 小时前
WAF与CDN在网络安全中的协同作用
网络·安全·web安全
Highcharts.js3 小时前
Highcharts Stock 股票图在交易系统中的应用思路
前端·数据可视化·股票图
teeeeeeemo3 小时前
前端模块化(commonJS和ES Module)
前端·笔记·es6·前端模块化
小old弟4 小时前
前端异常隔离方案:Proxy代理、Web Workers和iframe
前端
脑子慢且灵4 小时前
【Web前端】JS+DOM来实现乌龟追兔子小游戏
java·开发语言·前端·js·dom
TimelessHaze4 小时前
前端面试必问:深浅拷贝从基础到手写,一篇讲透
前端·trae