Jinja2模版介绍

注:本文demo使用ansible2.7稳定版

在ansible基础-变量的「8.2 模版使用变量」章节中关于模版与变量也有所提及,有兴趣的同学可以去回顾一下。

ansible通过Jinja2模版来实现动态表达式和变量的引用,模版的执行都是在ansible控制端完成的,所以理论上python的jinja2模块在控制端存在就能满足需求。

Jinja2模版都可以怎么使用?(分类)

  1. playbook文件中引用Jinja2模版实现动态表达式和变量的引用。
  2. 模版文件(roles/templates/xxx.j2)中引用Jinja2模版实现配置文件内容的拼接。

为什么要使用Jinja2模版?(好处)

  1. 使用过滤器、插件、测试变量等能够非常简单的实现一些小型的函数运算,使部署代码更加简洁高效。
  2. 适用性更加广泛,使部署代码更加灵活。

相比较于python原生的Jinja2模版,ansible扩展了很多过滤器和测试变量,同时也添加了一个新的插件「lookups」。

关于jinja2模版的基础语法和使用,因为篇幅原因,这里不再扩展。本文着重介绍下过滤器。

数据格式化过滤器

过滤器「to_json」「to_yaml」,将变量转换为json和yaml格式

{{ some_variable | to_json }}
{{ some_variable | to_yaml }}

过滤器「to_nice_json」「to_nice_yaml」,将变量转换为更加友好的json和yaml格式

{{ some_variable | to_nice_json }}
{{ some_variable | to_nice_yaml }}

也可以自定义缩进的大小

{{ some_variable | to_nice_json(indent=2) }}
{{ some_variable | to_nice_yaml(indent=8) }}

过滤器「from_json」「from_yaml」,从已经格式化好了的变量读取数据:

{{ some_variable | from_json }}
{{ some_variable | from_yaml }}

「from_json」示例,从file.json文件读取json数据:

tasks:- shell: cat /some/path/to/file.jsonregister: result- set_fact:myvar: "{{ result.stdout | from_json }}"

过滤器「from_yaml_all」,用来解析YAML多文档文件

tasks:- shell: cat /some/path/to/multidoc-file.yamlregister: result- debug:msg: '{{ item }}'loop: '{{ result.stdout | from_yaml_all | list }}'

YAML多文档文件指一个文件中包含多个yaml数据文档,例如:

---
part_one: one
...---
part_two: two
...

变量强制定义过滤器

当我们引用一个未被定义的变量时,ansible默认会报错,当然我们可以通过更改ansible.cfg配置项的方式关闭这种机制(即设置[defaults]字段下的error_on_undefined_vars = False)。

在关闭这个机制的情况下,如果我们想让ansible强制检查某个变量是否定义,可以使用「mandatory」过滤器,写法如下:

{{ variable | mandatory }}

此时,如果变量「variable」被定义了,则引用,否则会报错:

fatal: [node1]: FAILED! => {"msg": "Mandatory variable 'aaa' not defined."}

变量默认值过滤器

「default」过滤器可以为未定义变量设置默认值,类似于roles/defaults/main.yaml里定义的变量,优先级最低(变量优先级参考ansible基础-变量)。

示例如下:

{{ some_variable | default(5) }}

另外,如果我们想将变量参数是false、False和空(None)视为未定义,则必须给defaults过滤器第二参数位置加上「true」:

{{ lookup('env', 'MY_USER') | default('admin', true) }}

上面示例中表示:从环境变量中查找「MU_USER」变量,如果变量值为false、False、空(None)、未定义则将其设置为「admin」。否则引用之前被定义的参数。

可删除参数过滤器

过滤器「omit」:在使用模块的时候,有些参数的存在与否可以取决于变量是否被定义:

- name: touch files with an optional modefile: dest={{ item.path }} state=touch mode={{ item.mode | default(omit) }}loop:- path: /tmp/foo- path: /tmp/bar- path: /tmp/bazmode: "0444"

上面示例表示:变量中如果定义了变量「mode」,file模块则使用mode参数,否则就不使用。

执行结果为「/tmp/foo」和「/tmp/bar」文件使用默认权限,「/tmp/baz」文件使用「0444」权限。

列表过滤器

过滤器「min」,获取最小值元素

{{ list1 | min }}

过滤器「max」,获取最大值元素

{{ [3, 4, 2] | max }}

过滤器「flatten」,扁平化列表元素

{{ [3, [4, 2] ] | flatten }}

转换结果为:

[3, 4, 2 ]

过滤器「flatten」,并且指定级别

{{ [3, [4, [2]] ] | flatten(levels=1) }}

只转换一级的列表元素,结果为:

[3, 4, [2] ]

过滤器「unique」,给列表元素去重

{{ list1 | unique }}

过滤器「union」,合并两个列表后去重

{{ list1 | union(list2) }}

过滤器「intersect」,取两个列表相同的元素

{{ list1 | intersect(list2) }}

过滤器「difference」,去掉list1中与list2相同的元素,返回list1中剩余的元素

{{ list1 | difference(list2) }}

过滤器「symmetric_difference」,去掉list1与list2相同的元素,返回list1和list2剩余元素的集合

{{ list1 | symmetric_difference(list2) }}

操作列表过滤器zip和zip_longest

过滤器「zip」,使两个列表元素递归的融合,生成一个「itertools.izip」生成器对象。

通常后面加上「list」过滤器来使用,表示list1[0]元素与list2[0]元素组合,作为新列表的第一个元素;list1[1]元素与list2[1]元素组合,作为新列表的第二个元素 ,以此类推…… 新列表元素个数以list1和list2中元素个数较少者为准。

如果文字描述不懂,看下面示例就懂了:

- name: give me list combo of two listsdebug:msg: "{{ [1,2,3,4,5] | zip(['a','b','c','d','e','f']) | list }}"

转换结果为:

    "msg": [[1,"a"],[2,"b"],[3,"c"],[4,"d"],[5,"e"]]

过滤器「zip_longest」,与「zip」过滤器合并原理相似,「zip_longest」可以对更多的列表进行操作,且新列表元素个数以被操作列表中元素个数最多者为准,此时就需要指定「fillvalue」参数作为补位填充。示例如下:

{{ [1,2,3] | zip_longest(['a','b','c','d','e','f'], [21, 22, 23], [100,200,300],fillvalue='X') | list }}

转换结果为:

 "msg": [[1,"a",21,100],[2,"b",22,200],[3,"c",23,300],["X","d","X","X"],["X","e","X","X"],["X","f","X","X"]]

转换结果

操作列表过滤器subelements

过滤器「subelements」,操作对象为列表,摘取列表中的一个元素(通常为一个字典),将这个字典元素作为原始列表的新元素,其他元素保持不变。

{{ users | subelements('groups', skip_missing=True) }}

上面语句会将:

users:- name: aliceauthorized:- /tmp/alice/onekey.pub- /tmp/alice/twokey.pubgroups:- wheel- docker- name: bobauthorized:- /tmp/bob/id_rsa.pubgroups:- docker

转换为:

-- name: alicegroups:- wheel- dockerauthorized:- /tmp/alice/onekey.pub- /tmp/alice/twokey.pub- wheel
-- name: alicegroups:- wheel- dockerauthorized:- /tmp/alice/onekey.pub- /tmp/alice/twokey.pub- docker
-- name: bobauthorized:- /tmp/bob/id_rsa.pubgroups:- docker- docker

列表与字典互相转换过滤器

过滤器「dict2items」,将字典变量转换为列表变量

{{ dict | dict2items }}

例如,可以将

tags:Application: paymentEnvironment: dev

转换为:

- key: Applicationvalue: payment
- key: Environmentvalue: dev

过滤器「items2dict」,将列表变量转换为字典变量,默认情况下,列表元素必须有「key:」和「 value」。例如:

tags:- key: Applicationvalue: payment- key: Environmentvalue: dev

转换为:

Application: payment
Environment: dev

当然我们也可以认为指定「key:」「value」的替代参数:

{{ tags | items2dict(key_name='key_spec', value_name='value_spec') }}

随机Mac地址数过滤器

过滤器「random_mac」,在一个MAC地址前缀的基础上,随机生成mac地址。

"{{ '52:54:00' | random_mac }}"
# => '52:54:00:ef:1c:03'

注:如果给出的MAC地址前缀格式有问题,ansible会报错。

随机数过滤器

过滤器「random」,用于生成随机数,操作对象可以是一个列表也可以是一个数字。

从列表里随机获取一个数值:

"{{ ['a','b','c'] | random }}"
# => 'c'

从数字0到60之间获取一个随机数:

"{{ 60 | random }} * * * * root /script/from/cron"
# => '21 * * * * root /script/from/cron'

从数字10到100之间获取一个随机数,间隔设置为10:

{{ 101 | random(1, 10) }}
# => 31
{{ 101 | random(start=1, step=10) }}
# => 51

添加「seed」参数可以根据指定变量获取一个随机数,用于满足幂等性需求:

"{{ 60 | random(seed=inventory_hostname) }} * * * * root /script/from/cron"

打乱列表顺序过滤器

过滤器「shuffle」,用于给一个列表重新排序,每次排序随机:

{{ ['a','b','c'] | shuffle }}
# => ['c','a','b']
{{ ['a','b','c'] | shuffle }}
# => ['b','c','a']

添加「seed」参数可以根据指定变量获取一个随机排序,用于满足幂等性要求,此时,每次执行playbook获取到的列表顺序是固定的:

{{ ['a','b','c'] | shuffle(seed=inventory_hostname) }}
# => ['b','a','c']

Json数据查询过滤器

过滤器「json_query」,用于从json数据变量中摘取出一部分数据:

例如,下面是一个完整的json格式的变量

domain_definition:domain:cluster:- name: "cluster1"- name: "cluster2"server:- name: "server11"cluster: "cluster1"port: "8080"- name: "server12"cluster: "cluster1"port: "8090"- name: "server21"cluster: "cluster2"port: "9080"- name: "server22"cluster: "cluster2"port: "9090"library:- name: "lib1"target: "cluster1"- name: "lib2"

从这个变量中摘取出所有的「name」:

- name: "Display all cluster names"debug:var: itemloop: "{{ domain_definition | json_query('domain.cluster[*].name') }}"

摘取cluster1的port:

- name: "Display all ports from cluster1"debug:var: itemloop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"vars:server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"

摘取cluster2的name和port:

- name: "Display all server ports and names from cluster1"debug:var: itemloop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"vars:server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"

IP地址过滤器

过滤器「ipaddr」,用于测试是否为IP地址格式:

{{ myvar | ipaddr }}

「ipaddr」过滤器也可以用于摘取出一个IP地址的指定信息:

例如,从一个CIDR摘取出IP地址信息:

{{ '192.0.2.1/24' | ipaddr('address') }}

输出结果为:

"msg": "192.0.2.1"

过滤器「ipv4」「ipv6」,用于检测ipv4和ipv6协议的IP地址:

{{ myvar | ipv4 }}
{{ myvar | ipv6 }}

哈希值过滤器

过滤器「hash」,用于获取字符串的hash值。

获取字符串的sha1哈希值:

{{ 'test1' | hash('sha1') }}

获取字符串的md5哈希值:

{{ 'test2' | hash('blowfish') }}

过滤器「checksum」,用于获取字符串的checksum:

{{ 'test2' | checksum }}

过滤器「password_hash」,用于获取一个密码的哈希值。

获取sha512密码哈希值,结果随机:

{{ 'passwordsaresecret' | password_hash('sha512') }}

获取sha256密码哈希值,并加盐处理,结果满足幂等性:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt') }}

根据主机名获取一个满足幂等原则的sha256密码,写法如下:

{{ 'secretpassword' | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }}

一些hash类型也允许提供「rounds」参数:

{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt', rounds=10000) }}

注:关于哈希加盐和rounds请自行Google。

操作字典元素过滤器

过滤器「combine」,用于合并字典数据。

默认情况下,不仅两个字典会被合并,字典数据也会被后面字典数据覆盖:

{{ {'a':1, 'b':2} | combine({'b':3, 'c':4}) }}

结果为:

{'a':1, 'b':3, 'c':4}

如果字典类型是多层全套字典,我们可以添加「resursive=True」参数进行内层字典融合:

{{ {'a':{'foo':1, 'bar':2}, 'b':2} | combine({'a':{'bar':3, 'baz':4}}, recursive=True) }}

结果为:

{'a':{'foo':1, 'bar':3, 'baz':4}, 'b':2}

多个字典递归融合:

{{ a | combine(b, c, d) }}

上述示例中,字典「d」会字典「c」进行合并与元素的覆盖,合并结果与字典「b」进行合并于覆盖,合并结果再与字典「a」进行合并与覆盖,返回最后的字典数据。

注:combine过滤器与ansible.cfg的「hash_behaviour」参数无关,即使「hash_behaviour」设置为了「replace」,在「combine」过滤器里依然会使用merge的方式进行融合。

参数提取过滤器

过滤器「map」,根据指定条件提取出列表或字典内的数据。

{{ [0,2] | map('extract', ['x','y','z']) | list }}
{{ ['x','y'] | map('extract', {'x': 42, 'y': 31}) | list }}

输出结果为:

['x', 'z']
[42, 31]

「map」还可以实现更加复杂的提取工作:

假设我想提取出主机组「nodes」下三个主机的「ansible_architecture」fact变量值,可以这样写:

{{ groups['nodes'] | map ('extract',hostvars,['ansible_architecture']) | list }}

输出结果为:

    "msg": ["x86_64","x86_64","x86_64"]

同理,如果我想查询三个节点的ip地址放到一个列表内,可以这样写:

{{ groups['nodes'] | map ('extract',hostvars,['ansible_default_ipv4','address']) | list }}

输出结果为:

    "msg": ["10.211.55.7","10.211.55.9","10.211.55.8"]

上面两个示例用一个比较简易的表达式表示如下,如果不理解可以当公式记住:

{{ ['a'] | map('extract', b, ['x','y']) | list }}

则会获取到b['a']['x']['y']的参数结果。

注释过滤器

过滤器「comment」,可以实现注释字符串的功能,默认为「#」注释。

{{ "Plain style (default)" | comment }}

结果为:

#
# Plain style (default)
#

我们也可以为 C (//...), C block (/*...*/), Erlang (%...) 和XML (<!--...-->)做注释,分别为:

{{ "C style" | comment('c') }}
{{ "C block style" | comment('cblock') }}
{{ "Erlang style" | comment('erlang') }}
{{ "XML style" | comment('xml') }}

使用「decoration」参数可以人为指定注释符号:

{{ "My Special Case" | comment(decoration="! ") }}

输出结果为:

!
! My Special Case
!

为了美观,我们也可以定制格式:

{{ "Custom style" | comment('plain', prefix='#######\n#', postfix='#\n#######\n   ###\n    #') }}

输出结果为:

#######
#
# Custom style
#
###########

「comment」也可以传递变量,例如「ansible_managed」变量为:

[defaults]
ansible_managed = This file is managed by Ansible.%ntemplate: {file}date: %Y-%m-%d %H:%M:%Suser: {uid}host: {host}

通过表达式:

{{ ansible_managed | comment }}

转化为:

#
# This file is managed by Ansible.
#
# template: /home/ansible/env/dev/ansible_managed/roles/role1/templates/test.j2
# date: 2015-09-10 11:02:58
# user: ansible
# host: myhost
#

解析url过滤器

过滤器「urlsplit」,用于分解一个url链接,取出我们需要的字段,直接上官网示例:

{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('hostname') }}
# => 'www.acme.com'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('netloc') }}
# => 'user:password@www.acme.com:9000'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('username') }}
# => 'user'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('password') }}
# => 'password'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('path') }}
# => '/dir/index.html'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('port') }}
# => '9000'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('scheme') }}
# => 'http'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('query') }}
# => 'query=term'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('fragment') }}
# => 'fragment'{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit }}
# =>
#   {
#       "fragment": "fragment",
#       "hostname": "www.acme.com",
#       "netloc": "user:password@www.acme.com:9000",
#       "password": "password",
#       "path": "/dir/index.html",
#       "port": 9000,
#       "query": "query=term",
#       "scheme": "http",
#       "username": "user"
#   }

正则过滤器

过滤器「regex_search」,用于对一个字符串的正则匹配查找

# search for "foo" in "foobar"
{{ 'foobar' | regex_search('(foo)') }}# will return empty if it cannot find a match
{{ 'ansible' | regex_search('(foobar)') }}# case insensitive search in multiline mode
{{ 'foo\nBAR' | regex_search("^bar", multiline=True, ignorecase=True) }}

过滤器「regex_findall」,用于对所有事件进行查找:

# Return a list of all IPv4 addresses in the string
{{ 'Some DNS servers are 8.8.8.8 and 8.8.4.4' | regex_findall('\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b') }}

过滤器「regex_replace」,用于对一个字符串进行文本替换:

# convert "ansible" to "able"
{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}# convert "foobar" to "bar"
{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}# convert "localhost:80" to "localhost, 80" using named groups
{{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}# convert "localhost:80" to "localhost"
{{ 'localhost:80' | regex_replace(':80') }}# add "https://" prefix to each item in a list
{{ hosts | map('regex_replace', '^(.*)$', 'https://\\1') | list }}

过滤器「regex_escape」,用于转义特殊字符串:

# convert '^f.*o(.*)$' to '\^f\.\*o\(\.\*\)\$'
{{ '^f.*o(.*)$' | regex_escape() }}

其他过滤器

过滤器「quote」,给字符串添加引号,在shell模块内使用

- shell: echo {{ string_value | quote }}

过滤器「ternary」,根据前面语句的真与假选择一个字符串

{{ (name == "John") | ternary('Mr','Ms') }}

上面示例表示:如果变量「name」的值为「John」则表达式返回字符串「Mr」,否则返回字符串「Ms」。

过滤器「join」,将列表转换成字符串,可以指定连接符

{{ list | join(" ") }}

过滤器「basename」,获取一个文件的绝对路径,例如将「foo.txt」转换为「/etc/asdf/foo.txt」

1{{ path | basename }}

过滤器「dirname」,获取一个文件或目录的上级目录

{{ path | dirname }}

例如:

「/etc/httpd/conf」将获取到「/etc/httpd」

「/etc/httpd/conf/」将获取到「/etc/httpd/conf」

「/etc/httpd/conf/httpd.conf」将获取到「/etc/httpd/conf」

过滤器「realpath」,获取一个链接文件的真实文件路径,默认是绝对路径

{{ path | realpath }}

获取「/etc」的相对路径

{{ path | relpath('/etc') }}

过滤器「splittext」,拆分字符串,将文件的位置提取出来作为一个单独的元素

# with path == 'nginx.conf' the return would be ('nginx', '.conf')
{{ path | splitext }}

过滤器「b64decode」「b64encode」,Base64编码与解码

{{ encoded | b64decode }}
{{ decoded | b64encode }}

过滤器「to_uuid」,根据一个字符串生成一个UUID

{{ hostname | to_uuid }}

过滤器「map」的另一个用法

# get a comma-separated list of the mount points (e.g. "/,/mnt/stuff") on a host
{{ ansible_mounts | map(attribute='mount') | join(',') }}

过滤器「to_datetime」,获取到的是日期对象

# Get total amount of seconds between two dates. Default date format is %Y-%m-%d %H:%M:%S but you can pass your own format
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime('%Y-%m-%d'))).total_seconds()  }}# Get remaining seconds after delta has been calculated. NOTE: This does NOT convert years, days, hours, etc to seconds. For that, use total_seconds()
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2016-08-14 18:00:00" | to_datetime)).seconds  }}
# This expression evaluates to "12" and not "132". Delta is 2 hours, 12 seconds# get amount of days between two dates. This returns only number of days and discards remaining hours, minutes, and seconds
{{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime('%Y-%m-%d'))).days  }}

格式化时间数据

# Display year-month-day
{{ '%Y-%m-%d' | strftime }}# Display hour:min:sec
{{ '%H:%M:%S' | strftime }}# Use ansible_date_time.epoch fact
{{ '%Y-%m-%d %H:%M:%S' | strftime(ansible_date_time.epoch) }}# Use arbitrary epoch value
{{ '%Y-%m-%d' | strftime(0) }}          # => 1970-01-01
{{ '%Y-%m-%d' | strftime(1441357287) }} # => 2015-09-04

过滤器「type_debug」,用于debug出数据类型

{{ myvar | type_debug }}

本节应该掌握的技能

  • 掌握Jinja2模版的使用分类和优点
  • 熟悉本文提到的过滤器,最少记住大概功能
  • 掌握在playbook和模版文件中使用过滤器的方法

参考链接

  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html
  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html

欢迎大家关注我的公众号:

转载于:https://www.cnblogs.com/mauricewei/p/10056379.html

ansible基础-Jinja2模版 | 过滤器相关推荐

  1. ansible基础-Jinja2模版 | 测试

    ansible基础-Jinja2模版 | 测试 一 简介 注:本文demo使用ansible2.7稳定版 Jinja2的测试语句被用来评估一个条件表达式,并且最终返回True或False,经常和「wh ...

  2. ansible基础-playbooks

    1. playbooks介绍 如果说ansible的modules是工具,inventory配置文件是原材料,那么playbook就是一封说明书,这里会记录任务是如何如何执行的,当然如果你愿意,这里也 ...

  3. Flask框架基础Jinja2模板

    Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 文章目录 Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 return 模板 Template 模板的使用 ...

  4. 《Ansible权威指南 》一第2章 Ansible基础元素介绍

    本节书摘来自华章出版社<Ansible权威指南 >一书中的第2章,第2.1节,李松涛 魏 巍 甘 捷 著更多章节内容可以访问云栖社区"华章计算机"公众号查看. 第2章 ...

  5. 5 JInja2模版(适用于Django和Flask)

    模版 在生产环节下,我们要把后端程序(其实就是python)计算出来的数据和html页面结合起来做,这个时候模版就派上大用处了. Flask下的模版---Jinja2 Jinja是日本寺庙的意思,并且 ...

  6. Ansible基础入门

    1.1 Ansible是什么         随着移动互联.物联网.互联网+.大数据.云计算等大规模应用的催生推动,以及人们日常生活的互联网化,互联网的蓬勃发展不仅冲击影响着整个经济体,更对人们的生活 ...

  7. ansible基础配置

    1.基础配置 1.1.环境 主机配置 ansible版本:2.7.4 控制端:centos7.4,IP:192.168.1.213,主机名:operation 被控制端: centos6.5,IP:1 ...

  8. Ansible基础概述

    一.Ansible简介 Ansible基于Python语言实现,由paramiko和PyYAML两个关键模块构建.Ansible的编排引擎可以出色地完成配置管理,流程控制,资源部署等多方面工作.Ans ...

  9. v-show组件 vue_Vue.js教程--基础(实例 模版语法template computed, watch v-if, v-show v-for, 一个组件的v-for.)...

    官网:https://cn.vuejs.org/v2/guide/index.html Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统. 视频教程:https: ...

最新文章

  1. 谷歌顶级量子科学家详述他为何从谷歌辞职
  2. linux avahi-daemon进程 网络服务 简介
  3. C#中小数点后保留两位小数,四舍五入的函数及使用方法
  4. 航海王_html_css3_旋转效果demo
  5. 2009年全国计算机软件考试推荐用书目录
  6. [C++11]字符串原始字面量
  7. 如何用Apache POI操作Excel文件-----如何用Apache POI 画一个离散图
  8. Linux CentOS完全卸载PHP
  9. CV学习笔记-图像滤波器
  10. 鼠标移到元素上 使hover事件不生效
  11. 报表工具Style Report报表打印功能
  12. 系统故障模拟及修复实验
  13. QT小项目-基于百度API的在线词典
  14. 王道考研系列 计算机考研 ——机试指南(第二版) 笔记(一)
  15. 思考: 现有 图像分割算法 的缺陷
  16. 手机计算机怎么玩24点游戏,计算器上的24点游戏怎么操作
  17. shell 小米system锁adb_小米Max刷机及ADB操作
  18. 转特权:NIOS2下的SDHC调试
  19. 微信公众号里打开链接下载APP
  20. CPU内部结构及工作原理

热门文章

  1. linux 0660 权限,CentOS 6上安装RAC权限绑定问题
  2. moia调度mysql到hive_创立打车软件Moia后,“不安分”的大众又收购一家移动支付公司PayByPhone...
  3. Linux服务器IP下了,linux – DDOS攻击下的服务器 – 如何查找IP?
  4. java 请求http get_java http get/post请求
  5. 【ruoyi若依】为当前页添加显示事件
  6. javascript 自定义类型
  7. Appium 与 Chromedriver
  8. windows cmd 如果失败了则暂停
  9. python写前端代码_哪种ide能同时写java和前端代码?
  10. mysqld --initialize --console失败_超详细的mysql awr监控系统系统搭建教程--第一部分...