0%

travis demo

安装 travis

1
2
3
4
5
6
7
$ apt-get install ruby
$ apt-get install ruby-dev
$ apt-get install build-essential
# gem update --system
# 下载很慢的话,切换镜像源
# gem sources --add https://gems.ruby-china.com/
$ gem install travis

登录

1
2
3
4
5
6
7
8
9
10
11
$ travis login

We need your GitHub login to identify you.
This information will not be sent to Travis CI, only to api.github.com.
The password will not be displayed.

Try running with --github-token or --auto if you don't want to enter your password anyway.

Username: xxx@xxx.xxx
Password for xxx@xxx.xxx: ***
Successfully logged in as xg4!

SSH 私钥进行加密处理

切换到 .travis.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 生成密钥,如果已存在无需生成
ssh-keygen -t rsa -C "xingor4@gmail.com"

# 使用Travis加密 --add 会自动将信息生成到 .travis.yml
$ travis encrypt-file ~/.ssh/id_rsa --add

Detected repository as xxx/xxx, is this correct? |yes| yes
encrypting ~/.ssh/id_rsa for xxx/xxx
storing result as id_rsa.enc
storing secure env variables for decryption

Make sure to add id_rsa.enc to the git repository.
Make sure not to add ~/.ssh/id_rsa to the git repository.
Commit all changes to your .travis.yml.

# 添加信任关系
ssh-copy-id -i deploy_rsa.pub <ssh-user>@<deploy-host>

# 将修改添加到git中
git add id_rsa.enc .travis.yml

设置权限

1
2
3
4
5
6
7
# .travis.yml
before_install:
# 自动生成
- openssl aes-256-cbc -K $encrypted_d89376f3278d_key -iv $encrypted_d89376f3278d_iv
-in id_rsa.enc -out ~/.ssh/id_rsa -d
# 设置权限
- chmod 600 ~/.ssh/id_rsa

主机验证

1
2
3
# .travis.yml
addons:
ssh_known_hosts: your-ip

Table of Contents

Referencing Issues

commit message 中包含下面的关键词 + issues id, 自动关闭 issues
关闭其他仓库 issues 可使用:username/repository#issue_number

  • close

  • closes

  • closed

  • fix

  • fixes

  • fixed

  • resolve

  • resolves

  • resolved

example

1
2
3
fix #234

closes #123, #245, #992

Badges

shields.io

Bitbucket issues
GitHub
GitHub package version
NodeVersion

Emojis

GitHub markdown 查看 emojis

People

:bowtie: :bowtie: :smile: :smile: :laughing: :laughing:
:blush: :blush: :smiley: :smiley: :relaxed: :relaxed:
:smirk: :smirk: :heart_eyes: :heart_eyes: :kissing_heart: :kissing_heart:
:kissing_closed_eyes: :kissing_closed_eyes: :flushed: :flushed: :relieved: :relieved:
:satisfied: :satisfied: :grin: :grin: :wink: :wink:
:stuck_out_tongue_winking_eye: :stuck_out_tongue_winking_eye: :stuck_out_tongue_closed_eyes: :stuck_out_tongue_closed_eyes: :grinning: :grinning:
:kissing: :kissing: :kissing_smiling_eyes: :kissing_smiling_eyes: :stuck_out_tongue: :stuck_out_tongue:
:sleeping: :sleeping: :worried: :worried: :frowning: :frowning:
:anguished: :anguished: :open_mouth: :open_mouth: :grimacing: :grimacing:
:confused: :confused: :hushed: :hushed: :expressionless: :expressionless:
:unamused: :unamused: :sweat_smile: :sweat_smile: :sweat: :sweat:
:disappointed_relieved: :disappointed_relieved: :weary: :weary: :pensive: :pensive:
:disappointed: :disappointed: :confounded: :confounded: :fearful: :fearful:
:cold_sweat: :cold_sweat: :persevere: :persevere: :cry: :cry:
:sob: :sob: :joy: :joy: :astonished: :astonished:
:scream: :scream: :neckbeard: :neckbeard: :tired_face: :tired_face:
:angry: :angry: :rage: :rage: :triumph: :triumph:
:sleepy: :sleepy: :yum: :yum: :mask: :mask:
:sunglasses: :sunglasses: :dizzy_face: :dizzy_face: :imp: :imp:
:smiling_imp: :smiling_imp: :neutral_face: :neutral_face: :no_mouth: :no_mouth:
:innocent: :innocent: :alien: :alien: :yellow_heart: :yellow_heart:
:blue_heart: :blue_heart: :purple_heart: :purple_heart: :heart: :heart:
:green_heart: :green_heart: :broken_heart: :broken_heart: :heartbeat: :heartbeat:
:heartpulse: :heartpulse: :two_hearts: :two_hearts: :revolving_hearts: :revolving_hearts:
:cupid: :cupid: :sparkling_heart: :sparkling_heart: :sparkles: :sparkles:
:star: :star: :star2: :star2: :dizzy: :dizzy:
:boom: :boom: :collision: :collision: :anger: :anger:
:exclamation: :exclamation: :question: :question: :grey_exclamation: :grey_exclamation:
:grey_question: :grey_question: :zzz: :zzz: :dash: :dash:
:sweat_drops: :sweat_drops: :notes: :notes: :musical_note: :musical_note:
:fire: :fire: :hankey: :hankey: :poop: :poop:
:shit: :shit: :+1: :+1: :thumbsup: :thumbsup:
:-1: :-1: :thumbsdown: :thumbsdown: :ok_hand: :ok_hand:
:punch: :punch: :facepunch: :facepunch: :fist: :fist:
:v: :v: :wave: :wave: :hand: :hand:
:raised_hand: :raised_hand: :open_hands: :open_hands: :point_up: :point_up:
:point_down: :point_down: :point_left: :point_left: :point_right: :point_right:
:raised_hands: :raised_hands: :pray: :pray: :point_up_2: :point_up_2:
:clap: :clap: :muscle: :muscle: :metal: :metal:
:fu: :fu: :walking: :walking: :runner: :runner:
:running: :running: :couple: :couple: :family: :family:
:two_men_holding_hands: :two_men_holding_hands: :two_women_holding_hands: :two_women_holding_hands: :dancer: :dancer:
:dancers: :dancers: :ok_woman: :ok_woman: :no_good: :no_good:
:information_desk_person: :information_desk_person: :raising_hand: :raising_hand: :bride_with_veil: :bride_with_veil:
:person_with_pouting_face: :person_with_pouting_face: :person_frowning: :person_frowning: :bow: :bow:
:couplekiss: :couplekiss: :couple_with_heart: :couple_with_heart: :massage: :massage:
:haircut: :haircut: :nail_care: :nail_care: :boy: :boy:
:girl: :girl: :woman: :woman: :man: :man:
:baby: :baby: :older_woman: :older_woman: :older_man: :older_man:
:person_with_blond_hair: :person_with_blond_hair: :man_with_gua_pi_mao: :man_with_gua_pi_mao: :man_with_turban: :man_with_turban:
:construction_worker: :construction_worker: :cop: :cop: :angel: :angel:
:princess: :princess: :smiley_cat: :smiley_cat: :smile_cat: :smile_cat:
:heart_eyes_cat: :heart_eyes_cat: :kissing_cat: :kissing_cat: :smirk_cat: :smirk_cat:
:scream_cat: :scream_cat: :crying_cat_face: :crying_cat_face: :joy_cat: :joy_cat:
:pouting_cat: :pouting_cat: :japanese_ogre: :japanese_ogre: :japanese_goblin: :japanese_goblin:
:see_no_evil: :see_no_evil: :hear_no_evil: :hear_no_evil: :speak_no_evil: :speak_no_evil:
:guardsman: :guardsman: :skull: :skull: :feet: :feet:
:lips: :lips: :kiss: :kiss: :droplet: :droplet:
:ear: :ear: :eyes: :eyes: :nose: :nose:
:tongue: :tongue: :love_letter: :love_letter: :bust_in_silhouette: :bust_in_silhouette:
:busts_in_silhouette: :busts_in_silhouette: :speech_balloon: :speech_balloon: :thought_balloon: :thought_balloon:
:feelsgood: :feelsgood: :finnadie: :finnadie: :goberserk: :goberserk:
:godmode: :godmode: :hurtrealbad: :hurtrealbad: :rage1: :rage1:
:rage2: :rage2: :rage3: :rage3: :rage4: :rage4:
:suspect: :suspect: :trollface: :trollface:

Nature

:sunny: :sunny: :umbrella: :umbrella: :cloud: :cloud:
:snowflake: :snowflake: :snowman: :snowman: :zap: :zap:
:cyclone: :cyclone: :foggy: :foggy: :ocean: :ocean:
:cat: :cat: :dog: :dog: :mouse: :mouse:
:hamster: :hamster: :rabbit: :rabbit: :wolf: :wolf:
:frog: :frog: :tiger: :tiger: :koala: :koala:
:bear: :bear: :pig: :pig: :pig_nose: :pig_nose:
:cow: :cow: :boar: :boar: :monkey_face: :monkey_face:
:monkey: :monkey: :horse: :horse: :racehorse: :racehorse:
:camel: :camel: :sheep: :sheep: :elephant: :elephant:
:panda_face: :panda_face: :snake: :snake: :bird: :bird:
:baby_chick: :baby_chick: :hatched_chick: :hatched_chick: :hatching_chick: :hatching_chick:
:chicken: :chicken: :penguin: :penguin: :turtle: :turtle:
:bug: :bug: :honeybee: :honeybee: :ant: :ant:
:beetle: :beetle: :snail: :snail: :octopus: :octopus:
:tropical_fish: :tropical_fish: :fish: :fish: :whale: :whale:
:whale2: :whale2: :dolphin: :dolphin: :cow2: :cow2:
:ram: :ram: :rat: :rat: :water_buffalo: :water_buffalo:
:tiger2: :tiger2: :rabbit2: :rabbit2: :dragon: :dragon:
:goat: :goat: :rooster: :rooster: :dog2: :dog2:
:pig2: :pig2: :mouse2: :mouse2: :ox: :ox:
:dragon_face: :dragon_face: :blowfish: :blowfish: :crocodile: :crocodile:
:dromedary_camel: :dromedary_camel: :leopard: :leopard: :cat2: :cat2:
:poodle: :poodle: :paw_prints: :paw_prints: :bouquet: :bouquet:
:cherry_blossom: :cherry_blossom: :tulip: :tulip: :four_leaf_clover: :four_leaf_clover:
:rose: :rose: :sunflower: :sunflower: :hibiscus: :hibiscus:
:maple_leaf: :maple_leaf: :leaves: :leaves: :fallen_leaf: :fallen_leaf:
:herb: :herb: :mushroom: :mushroom: :cactus: :cactus:
:palm_tree: :palm_tree: :evergreen_tree: :evergreen_tree: :deciduous_tree: :deciduous_tree:
:chestnut: :chestnut: :seedling: :seedling: :blossom: :blossom:
:ear_of_rice: :ear_of_rice: :shell: :shell: :globe_with_meridians: :globe_with_meridians:
:sun_with_face: :sun_with_face: :full_moon_with_face: :full_moon_with_face: :new_moon_with_face: :new_moon_with_face:
:new_moon: :new_moon: :waxing_crescent_moon: :waxing_crescent_moon: :first_quarter_moon: :first_quarter_moon:
:waxing_gibbous_moon: :waxing_gibbous_moon: :full_moon: :full_moon: :waning_gibbous_moon: :waning_gibbous_moon:
:last_quarter_moon: :last_quarter_moon: :waning_crescent_moon: :waning_crescent_moon: :last_quarter_moon_with_face: :last_quarter_moon_with_face:
:first_quarter_moon_with_face: :first_quarter_moon_with_face: :moon: :moon: :earth_africa: :earth_africa:
:earth_americas: :earth_americas: :earth_asia: :earth_asia: :volcano: :volcano:
:milky_way: :milky_way: :partly_sunny: :partly_sunny: :octocat: :octocat:
:squirrel: :squirrel:

Objects

:bamboo: :bamboo: :gift_heart: :gift_heart: :dolls: :dolls:
:school_satchel: :school_satchel: :mortar_board: :mortar_board: :flags: :flags:
:fireworks: :fireworks: :sparkler: :sparkler: :wind_chime: :wind_chime:
:rice_scene: :rice_scene: :jack_o_lantern: :jack_o_lantern: :ghost: :ghost:
:santa: :santa: :christmas_tree: :christmas_tree: :gift: :gift:
:bell: :bell: :no_bell: :no_bell: :tanabata_tree: :tanabata_tree:
:tada: :tada: :confetti_ball: :confetti_ball: :balloon: :balloon:
:crystal_ball: :crystal_ball: :cd: :cd: :dvd: :dvd:
:floppy_disk: :floppy_disk: :camera: :camera: :video_camera: :video_camera:
:movie_camera: :movie_camera: :computer: :computer: :tv: :tv:
:iphone: :iphone: :phone: :phone: :telephone: :telephone:
:telephone_receiver: :telephone_receiver: :pager: :pager: :fax: :fax:
:minidisc: :minidisc: :vhs: :vhs: :sound: :sound:
:speaker: :speaker: :mute: :mute: :loudspeaker: :loudspeaker:
:mega: :mega: :hourglass: :hourglass: :hourglass_flowing_sand: :hourglass_flowing_sand:
:alarm_clock: :alarm_clock: :watch: :watch: :radio: :radio:
:satellite: :satellite: :loop: :loop: :mag: :mag:
:mag_right: :mag_right: :unlock: :unlock: :lock: :lock:
:lock_with_ink_pen: :lock_with_ink_pen: :closed_lock_with_key: :closed_lock_with_key: :key: :key:
:bulb: :bulb: :flashlight: :flashlight: :high_brightness: :high_brightness:
:low_brightness: :low_brightness: :electric_plug: :electric_plug: :battery: :battery:
:calling: :calling: :email: :email: :mailbox: :mailbox:
:postbox: :postbox: :bath: :bath: :bathtub: :bathtub:
:shower: :shower: :toilet: :toilet: :wrench: :wrench:
:nut_and_bolt: :nut_and_bolt: :hammer: :hammer: :seat: :seat:
:moneybag: :moneybag: :yen: :yen: :dollar: :dollar:
:pound: :pound: :euro: :euro: :credit_card: :credit_card:
:money_with_wings: :money_with_wings: :e-mail: :e-mail: :inbox_tray: :inbox_tray:
:outbox_tray: :outbox_tray: :envelope: :envelope: :incoming_envelope: :incoming_envelope:
:postal_horn: :postal_horn: :mailbox_closed: :mailbox_closed: :mailbox_with_mail: :mailbox_with_mail:
:mailbox_with_no_mail: :mailbox_with_no_mail: :door: :door: :smoking: :smoking:
:bomb: :bomb: :gun: :gun: :hocho: :hocho:
:pill: :pill: :syringe: :syringe: :page_facing_up: :page_facing_up:
:page_with_curl: :page_with_curl: :bookmark_tabs: :bookmark_tabs: :bar_chart: :bar_chart:
:chart_with_upwards_trend: :chart_with_upwards_trend: :chart_with_downwards_trend: :chart_with_downwards_trend: :scroll: :scroll:
:clipboard: :clipboard: :calendar: :calendar: :date: :date:
:card_index: :card_index: :file_folder: :file_folder: :open_file_folder: :open_file_folder:
:scissors: :scissors: :pushpin: :pushpin: :paperclip: :paperclip:
:black_nib: :black_nib: :pencil2: :pencil2: :straight_ruler: :straight_ruler:
:triangular_ruler: :triangular_ruler: :closed_book: :closed_book: :green_book: :green_book:
:blue_book: :blue_book: :orange_book: :orange_book: :notebook: :notebook:
:notebook_with_decorative_cover: :notebook_with_decorative_cover: :ledger: :ledger: :books: :books:
:bookmark: :bookmark: :name_badge: :name_badge: :microscope: :microscope:
:telescope: :telescope: :newspaper: :newspaper: :football: :football:
:basketball: :basketball: :soccer: :soccer: :baseball: :baseball:
:tennis: :tennis: :8ball: :8ball: :rugby_football: :rugby_football:
:bowling: :bowling: :golf: :golf: :mountain_bicyclist: :mountain_bicyclist:
:bicyclist: :bicyclist: :horse_racing: :horse_racing: :snowboarder: :snowboarder:
:swimmer: :swimmer: :surfer: :surfer: :ski: :ski:
:spades: :spades: :hearts: :hearts: :clubs: :clubs:
:diamonds: :diamonds: :gem: :gem: :ring: :ring:
:trophy: :trophy: :musical_score: :musical_score: :musical_keyboard: :musical_keyboard:
:violin: :violin: :space_invader: :space_invader: :video_game: :video_game:
:black_joker: :black_joker: :flower_playing_cards: :flower_playing_cards: :game_die: :game_die:
:dart: :dart: :mahjong: :mahjong: :clapper: :clapper:
:memo: :memo: :pencil: :pencil: :book: :book:
:art: :art: :microphone: :microphone: :headphones: :headphones:
:trumpet: :trumpet: :saxophone: :saxophone: :guitar: :guitar:
:shoe: :shoe: :sandal: :sandal: :high_heel: :high_heel:
:lipstick: :lipstick: :boot: :boot: :shirt: :shirt:
:tshirt: :tshirt: :necktie: :necktie: :womans_clothes: :womans_clothes:
:dress: :dress: :running_shirt_with_sash: :running_shirt_with_sash: :jeans: :jeans:
:kimono: :kimono: :bikini: :bikini: :ribbon: :ribbon:
:tophat: :tophat: :crown: :crown: :womans_hat: :womans_hat:
:mans_shoe: :mans_shoe: :closed_umbrella: :closed_umbrella: :briefcase: :briefcase:
:handbag: :handbag: :pouch: :pouch: :purse: :purse:
:eyeglasses: :eyeglasses: :fishing_pole_and_fish: :fishing_pole_and_fish: :coffee: :coffee:
:tea: :tea: :sake: :sake: :baby_bottle: :baby_bottle:
:beer: :beer: :beers: :beers: :cocktail: :cocktail:
:tropical_drink: :tropical_drink: :wine_glass: :wine_glass: :fork_and_knife: :fork_and_knife:
:pizza: :pizza: :hamburger: :hamburger: :fries: :fries:
:poultry_leg: :poultry_leg: :meat_on_bone: :meat_on_bone: :spaghetti: :spaghetti:
:curry: :curry: :fried_shrimp: :fried_shrimp: :bento: :bento:
:sushi: :sushi: :fish_cake: :fish_cake: :rice_ball: :rice_ball:
:rice_cracker: :rice_cracker: :rice: :rice: :ramen: :ramen:
:stew: :stew: :oden: :oden: :dango: :dango:
:egg: :egg: :bread: :bread: :doughnut: :doughnut:
:custard: :custard: :icecream: :icecream: :ice_cream: :ice_cream:
:shaved_ice: :shaved_ice: :birthday: :birthday: :cake: :cake:
:cookie: :cookie: :chocolate_bar: :chocolate_bar: :candy: :candy:
:lollipop: :lollipop: :honey_pot: :honey_pot: :apple: :apple:
:green_apple: :green_apple: :tangerine: :tangerine: :lemon: :lemon:
:cherries: :cherries: :grapes: :grapes: :watermelon: :watermelon:
:strawberry: :strawberry: :peach: :peach: :melon: :melon:
:banana: :banana: :pear: :pear: :pineapple: :pineapple:
:sweet_potato: :sweet_potato: :eggplant: :eggplant: :tomato: :tomato:
:corn: :corn: :package: :package:

Places

:house: :house: :house_with_garden: :house_with_garden: :school: :school:
:office: :office: :post_office: :post_office: :hospital: :hospital:
:bank: :bank: :convenience_store: :convenience_store: :love_hotel: :love_hotel:
:hotel: :hotel: :wedding: :wedding: :church: :church:
:department_store: :department_store: :european_post_office: :european_post_office: :city_sunrise: :city_sunrise:
:city_sunset: :city_sunset: :japanese_castle: :japanese_castle: :european_castle: :european_castle:
:tent: :tent: :factory: :factory: :tokyo_tower: :tokyo_tower:
:japan: :japan: :mount_fuji: :mount_fuji: :sunrise_over_mountains: :sunrise_over_mountains:
:sunrise: :sunrise: :stars: :stars: :statue_of_liberty: :statue_of_liberty:
:bridge_at_night: :bridge_at_night: :carousel_horse: :carousel_horse: :rainbow: :rainbow:
:ferris_wheel: :ferris_wheel: :fountain: :fountain: :roller_coaster: :roller_coaster:
:ship: :ship: :speedboat: :speedboat: :boat: :boat:
:sailboat: :sailboat: :rowboat: :rowboat: :anchor: :anchor:
:rocket: :rocket: :airplane: :airplane: :helicopter: :helicopter:
:steam_locomotive: :steam_locomotive: :tram: :tram: :mountain_railway: :mountain_railway:
:bike: :bike: :aerial_tramway: :aerial_tramway: :suspension_railway: :suspension_railway:
:mountain_cableway: :mountain_cableway: :tractor: :tractor: :blue_car: :blue_car:
:oncoming_automobile: :oncoming_automobile: :car: :car: :red_car: :red_car:
:taxi: :taxi: :oncoming_taxi: :oncoming_taxi: :articulated_lorry: :articulated_lorry:
:bus: :bus: :oncoming_bus: :oncoming_bus: :rotating_light: :rotating_light:
:police_car: :police_car: :oncoming_police_car: :oncoming_police_car: :fire_engine: :fire_engine:
:ambulance: :ambulance: :minibus: :minibus: :truck: :truck:
:train: :train: :station: :station: :train2: :train2:
:bullettrain_front: :bullettrain_front: :bullettrain_side: :bullettrain_side: :light_rail: :light_rail:
:monorail: :monorail: :railway_car: :railway_car: :trolleybus: :trolleybus:
:ticket: :ticket: :fuelpump: :fuelpump: :vertical_traffic_light: :vertical_traffic_light:
:traffic_light: :traffic_light: :warning: :warning: :construction: :construction:
:beginner: :beginner: :atm: :atm: :slot_machine: :slot_machine:
:busstop: :busstop: :barber: :barber: :hotsprings: :hotsprings:
:checkered_flag: :checkered_flag: :crossed_flags: :crossed_flags: :izakaya_lantern: :izakaya_lantern:
:moyai: :moyai: :circus_tent: :circus_tent: :performing_arts: :performing_arts:
:round_pushpin: :round_pushpin: :triangular_flag_on_post: :triangular_flag_on_post: :jp: :jp:
:kr: :kr: :cn: :cn: :us: :us:
:fr: :fr: :es: :es: :it: :it:
:ru: :ru: :gb: :gb: :uk: :uk:
:de: :de:

Symbols

:one: :one: :two: :two: :three: :three:
:four: :four: :five: :five: :six: :six:
:seven: :seven: :eight: :eight: :nine: :nine:
:keycap_ten: :keycap_ten: :1234: :1234: :zero: :zero:
:hash: :hash: :symbols: :symbols: :arrow_backward: :arrow_backward:
:arrow_down: :arrow_down: :arrow_forward: :arrow_forward: :arrow_left: :arrow_left:
:capital_abcd: :capital_abcd: :abcd: :abcd: :abc: :abc:
:arrow_lower_left: :arrow_lower_left: :arrow_lower_right: :arrow_lower_right: :arrow_right: :arrow_right:
:arrow_up: :arrow_up: :arrow_upper_left: :arrow_upper_left: :arrow_upper_right: :arrow_upper_right:
:arrow_double_down: :arrow_double_down: :arrow_double_up: :arrow_double_up: :arrow_down_small: :arrow_down_small:
:arrow_heading_down: :arrow_heading_down: :arrow_heading_up: :arrow_heading_up: :leftwards_arrow_with_hook: :leftwards_arrow_with_hook:
:arrow_right_hook: :arrow_right_hook: :left_right_arrow: :left_right_arrow: :arrow_up_down: :arrow_up_down:
:arrow_up_small: :arrow_up_small: :arrows_clockwise: :arrows_clockwise: :arrows_counterclockwise: :arrows_counterclockwise:
:rewind: :rewind: :fast_forward: :fast_forward: :information_source: :information_source:
:ok: :ok: :twisted_rightwards_arrows: :twisted_rightwards_arrows: :repeat: :repeat:
:repeat_one: :repeat_one: :new: :new: :top: :top:
:up: :up: :cool: :cool: :free: :free:
:ng: :ng: :cinema: :cinema: :koko: :koko:
:signal_strength: :signal_strength: :u5272: :u5272: :u5408: :u5408:
:u55b6: :u55b6: :u6307: :u6307: :u6708: :u6708:
:u6709: :u6709: :u6e80: :u6e80: :u7121: :u7121:
:u7533: :u7533: :u7a7a: :u7a7a: :u7981: :u7981:
:sa: :sa: :restroom: :restroom: :mens: :mens:
:womens: :womens: :baby_symbol: :baby_symbol: :no_smoking: :no_smoking:
:parking: :parking: :wheelchair: :wheelchair: :metro: :metro:
:baggage_claim: :baggage_claim: :accept: :accept: :wc: :wc:
:potable_water: :potable_water: :put_litter_in_its_place: :put_litter_in_its_place: :secret: :secret:
:congratulations: :congratulations: :m: :m: :passport_control: :passport_control:
:left_luggage: :left_luggage: :customs: :customs: :ideograph_advantage: :ideograph_advantage:
:cl: :cl: :sos: :sos: :id: :id:
:no_entry_sign: :no_entry_sign: :underage: :underage: :no_mobile_phones: :no_mobile_phones:
:do_not_litter: :do_not_litter: :non-potable_water: :non-potable_water: :no_bicycles: :no_bicycles:
:no_pedestrians: :no_pedestrians: :children_crossing: :children_crossing: :no_entry: :no_entry:
:eight_spoked_asterisk: :eight_spoked_asterisk: :eight_pointed_black_star: :eight_pointed_black_star: :heart_decoration: :heart_decoration:
:vs: :vs: :vibration_mode: :vibration_mode: :mobile_phone_off: :mobile_phone_off:
:chart: :chart: :currency_exchange: :currency_exchange: :aries: :aries:
:taurus: :taurus: :gemini: :gemini: :cancer: :cancer:
:leo: :leo: :virgo: :virgo: :libra: :libra:
:scorpius: :scorpius: :sagittarius: :sagittarius: :capricorn: :capricorn:
:aquarius: :aquarius: :pisces: :pisces: :ophiuchus: :ophiuchus:
:six_pointed_star: :six_pointed_star: :negative_squared_cross_mark: :negative_squared_cross_mark: :a: :a:
:b: :b: :ab: :ab: :o2: :o2:
:diamond_shape_with_a_dot_inside: :diamond_shape_with_a_dot_inside: :recycle: :recycle: :end: :end:
:on: :on: :soon: :soon: :clock1: :clock1:
:clock130: :clock130: :clock10: :clock10: :clock1030: :clock1030:
:clock11: :clock11: :clock1130: :clock1130: :clock12: :clock12:
:clock1230: :clock1230: :clock2: :clock2: :clock230: :clock230:
:clock3: :clock3: :clock330: :clock330: :clock4: :clock4:
:clock430: :clock430: :clock5: :clock5: :clock530: :clock530:
:clock6: :clock6: :clock630: :clock630: :clock7: :clock7:
:clock730: :clock730: :clock8: :clock8: :clock830: :clock830:
:clock9: :clock9: :clock930: :clock930: :heavy_dollar_sign: :heavy_dollar_sign:
:copyright: :copyright: :registered: :registered: :tm: :tm:
:x: :x: :heavy_exclamation_mark: :heavy_exclamation_mark: :bangbang: :bangbang:
:interrobang: :interrobang: :o: :o: :heavy_multiplication_x: :heavy_multiplication_x:
:heavy_plus_sign: :heavy_plus_sign: :heavy_minus_sign: :heavy_minus_sign: :heavy_division_sign: :heavy_division_sign:
:white_flower: :white_flower: :100: :100: :heavy_check_mark: :heavy_check_mark:
:ballot_box_with_check: :ballot_box_with_check: :radio_button: :radio_button: :link: :link:
:curly_loop: :curly_loop: :wavy_dash: :wavy_dash: :part_alternation_mark: :part_alternation_mark:
:trident: :trident: :black_square: :black_square: :white_square: :white_square:
:white_check_mark: :white_check_mark: :black_square_button: :black_square_button: :white_square_button: :white_square_button:
:black_circle: :black_circle: :white_circle: :white_circle: :red_circle: :red_circle:
:large_blue_circle: :large_blue_circle: :large_blue_diamond: :large_blue_diamond: :large_orange_diamond: :large_orange_diamond:
:small_blue_diamond: :small_blue_diamond: :small_orange_diamond: :small_orange_diamond: :small_red_triangle: :small_red_triangle:
:small_red_triangle_down: :small_red_triangle_down: :shipit: :shipit: :sparkle: :sparkle:
:back: :back:

Table of Contents

ssh-copy-id

将本机主机的公钥复制到远程主机的 authorized_keys 文件上,ssh-copy-id 命令也会给远程主机的用户主目录(home)和 ~/.ssh~/.ssh/authorized_keys 设置合适的权限

  • 语法

    1
    $ ssh-copy-id [-i [identity_file]] [user@]machine
  • 参数

    • -i : 指定公钥文件
  • example

    1
    2
    $ ssh-copy-id user@server
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub user@server

scp

  • 语法

    1
    2
    3
    scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
    [-l limit] [-o ssh_option] [-P port] [-S program]
    [[user@]host1:]file1 [...] [[user@]host2:]file2
  • 简易写法

    1
    $ scp [可选参数] file_source file_target
  • 参数:

    • -1 : 强制 scp 命令使用协议 ssh1

    • -2 : 强制 scp 命令使用协议 ssh2

    • -4 : 强制 scp 命令只使用 IPv4 寻址

    • -6 : 强制 scp 命令只使用 IPv6 寻址

    • -B : 使用批处理模式(传输过程中不询问传输口令或短语)

    • -C : 允许压缩。(将-C 标志传递给 ssh,从而打开压缩功能)

    • -p : 保留原文件的修改时间,访问时间和访问权限

    • -q : 不显示传输进度条

    • -r : 递归复制整个目录

    • -v : 详细方式显示输出。scp 和 ssh(1)会显示出整个过程的调试信息。这些信息用于调试连接,验证和配置问题

    • -c cipher : 以 cipher 将数据传输进行加密,这个选项将直接传递给 ssh

    • -F ssh_config : 指定一个替代的 ssh 配置文件,此参数直接传递给 ssh

    • -i identity_file : 从指定文件中读取传输时使用的密钥文件,此参数直接传递给 ssh

    • -l limit : 限定用户所能使用的带宽,以 Kbit/s 为单位

    • -o ssh_option : 如果习惯于使用 ssh_config(5)中的参数传递方式

    • -P port : 注意是大写的 P, port 是指定数据传输用到的端口号

    • -S program : 指定加密传输时所使用的程序。此程序必须能够理解 ssh(1)的选项

  • example

    1
    2
    3
    4
    5
    6
    7
    $ scp local_file remote_username@remote_ip:remote_folder
    # or
    $ scp local_file remote_username@remote_ip:remote_file
    # or
    $ scp local_file remote_ip:remote_folder
    # or
    $ scp local_file remote_ip:remote_file

Table of Contents

commit message

1
type(scope?): subject  #scope is optional
  • feat: 新功能

  • fix: bug 修复

  • docs: 文档修改

  • style: 不影响代码的更改(如空格,格式,缺少分号等)

  • refactor: 代码重构,既不修复错误也不添加功能

  • perf: 代码更改可以提高性能

  • test: 添加缺失或更正现有测试

  • build: build 相关,npm scripts

  • ci: CI 相关

  • chore: 对构建过程或辅助工具和库(如文档生成)的更改

  • revert: 版本回退

server

  1. 创建 git 用户,运行 git 服务

    1
    2
    3
    4
    5
    # 添加git账户
    $ adduser git

    # 修改git的密码
    $ passwd git
  2. 禁止 git 用户的 shell 登录

    出于安全考虑,创建的 git 用户不允许登录 shell,找到 /etc/passwd

    1
    2
    3
    $ git:x:1000:1000::/home/git:/bin/bash
    # 改为
    $ git:x:1000:1000::/home/git:/usr/bin/git-shell
  3. 免密登录

    1
    2
    3
    4
    5
    6
    7
    $ mkdir /home/git/.ssh
    $ chmod 700 /home/git/.ssh
    $ touch /home/git/.ssh/authorized_keys
    $ chmod 600 /home/git/.ssh/authorized_keys

    # 如果使用 sudo 创建,需要将 owner 改为 git
    $ chown -R git:git /home/git/

    编辑 /home/git/.ssh/authorized_keys 将客户端公钥放入

  4. 初始化 git 仓库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ mkdir /xg4
    $ chown git:git /xg4/
    $ cd /xg4

    # 创建空的git仓库
    $ git init --bare test.git
    Initialized empty Git repository in /xg4/test.git/

    # 将仓库所属用户改为git
    $ chown -R git:git test.git

hooks

  • client hooks: (commit hooks, email hooks, other hooks)

    • commit hooks

      • pre-commit

      • prepare-commit-msg

      • commit-msg

      • post-commit

    • email hooks

      • applypatch-msg

      • pre-applypatch

      • post-applypaych

    • other hooks:

      • pre-rebase

      • post-checkout

      • post-merge

  • server hooks:

    • pre-receive

    • post-receive

    • update

  1. 创建 git server 仓库

    1
    2
    $ cd /xg4
    $ git init --bare test.git
  2. 创建工作目录 git 仓库

    1
    2
    3
    4
    5
    $ cd /var/www
    $ git clone /xg4/test.git
    # or
    $ git init
    $ git remote add origin /xg4/test.git
  3. 改变所属用户和用户组,获得权限

    1
    2
    $ chown -R git:git /xg4/test.git
    $ chown -R git:git /var/www/test
  4. 设置 git hooks

    1
    2
    cd /xg4/test.git/hooks/
    vim post-receive

    post-receive 文件内容

    1
    2
    3
    4
    #!/bin/sh
    unset GIT_DIR
    cd /var/www/test
    git pull origin master
    1
    2
    # 赋予 post-receive 文件可执行权限
    $ chmod +x .git/hooks/post-receive

浏览器环境下的 javascript API、Utils

Table of Contents

insertAdjacentElement

可以通过不同的参数实现 jQueryappend | prepend | after | before

1
<div id="parent"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const parent = document.getElementById('parent')
const node = document.createElement('span')
// 插入到指定元素内部的尾部
// 等价于 $(parent).append(node)
parent.insertAdjacentElement('beforeend', node)

// 插入到指定元素内部的头部
// 等价于 $(parent).prepend(node)
parent.insertAdjacentElement('afterbegin', node)

// 插入到指定元素后面
// 等价于 $(parent).after(node)
parent.insertAdjacentElement('afterend', node)

// 插入到指定元素前面
// 等价于 $(parent).after(node)
parent.insertAdjacentElement('beforebegin', node)

getBoundingClientRect

element.getBoundingClientRect() 获取元素相对浏览器左上角的偏移量以及元素尺寸信息, 返回值是一个 rect 对象, 其中包括:
left: 元素左上角距离浏览器左上角的 X 轴偏移
top: 元素左上角距离浏览器左上角的 Y 轴偏移
width: 元素宽度
height: 元素高度
right: 元素右下角距离浏览器左上角的 X 轴偏移)
bottom: 元素右下角距离浏览器左上角的 Y 轴偏移
x: 同 left
y: 同 top

可以判断元素是否已经进入可视区域

getBoundingClientRect 会受到 transform 的影响, 比如你的元素设置了 transform:scale(2), 那么 getBoundingClientRect 返回的 width 会是元素实际宽度的 2 倍, top 等位置信息也会因为元素尺寸变化而发生变化

contains

node.contains(otherNode) 检查传入节点是否为该节点的子孙节点

1
2
3
function isInPage(node) {
return node === document.body ? false : document.body.contains(node)
}

compareDocumentPosition

node.compareDocumentPosition(otherNode) 可以比较当前节点与任意文档中的另一个节点的位置关系

MutationObserver

监听 DOM 元素的变化触发回调,可监视的变化有:属性(attribute)/文本(character),同时支持监听子孙节点(childList/subtree)

1
2
3
4
5
6
7
8
9
const observer = new MutationObserver(() => {
console.log('change')
})

// 监听
observer.observe(el, { childList: true, subtree: true })

// 销毁
observer.disconnect()

getBattery

电池状态 navigator.getBattery()

download

利用 html5 a 标签的 download 属性进行下载

1
2
3
4
5
6
7
8
9
10
11
12
const download = (rawData, name = 'file.json') => {
const url = URL.createObjectURL(rawData)
const a = document.createElement('a')
a.download = name
a.href = url
a.style.display = 'none'
// 兼容 firefox ,必须添加到 DOM 中才能触发下载
document.body.append(a) // document.body.appendChild(a)
a.click()
a.remove() // document.body.removeChild(a)
URL.revokeObjectURL(url)
}

fullScreen

  • toFullScreen

    全屏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function toFullScreen(el = document.body) {
    el.webkitRequestFullScreen
    ? el.webkitRequestFullScreen()
    : el.mozRequestFullScreen
    ? el.mozRequestFullScreen()
    : el.msRequestFullscreen
    ? el.msRequestFullscreen()
    : el.requestFullScreen
    ? el.requestFullScreen()
    : alert('浏览器不支持全屏')
    }
  • exitFullscreen

    退出全屏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function exitFullscreen(el = parent.document) {
    el.webkitCancelFullScreen
    ? el.webkitCancelFullScreen()
    : el.mozCancelFullScreen
    ? el.mozCancelFullScreen()
    : el.cancelFullScreen
    ? el.cancelFullScreen()
    : el.msExitFullscreen
    ? el.msExitFullscreen()
    : el.exitFullscreen
    ? el.exitFullscreen()
    : alert('切换失败,可尝试Esc退出')
    }

requestAnimationFrame

新的动画 API,也可用于性能监控

GitHub - raf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
window.requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60)
}

window.cancelAnimationFrame =
window.cancelAnimationFrame ||
Window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.msCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function(id) {
window.clearTimeout(id)
}

performance

利用 performance.timing 进行性能分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
window.onload = function() {
setTimeout(function() {
const t = performance.timing
console.log(
'DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart).toFixed(0)
)
console.log('TCP链接耗时 :' + (t.connectEnd - t.connectStart).toFixed(0))
console.log(
'request请求耗时 :' + (t.responseEnd - t.responseStart).toFixed(0)
)
console.log(
'解析dom树耗时 :' + (t.domComplete - t.domInteractive).toFixed(0)
)
console.log(
'白屏时间 :' + (t.responseStart - t.navigationStart).toFixed(0)
)
console.log(
'domready时间 :' +
(t.domContentLoadedEventEnd - t.navigationStart).toFixed(0)
)
console.log(
'onload时间 :' + (t.loadEventEnd - t.navigationStart).toFixed(0)
)

if ((t = performance.memory)) {
console.log(
'js内存使用占比 :' +
((t.usedJSHeapSize / t.totalJSHeapSize) * 100).toFixed(2) +
'%'
)
}
})
}

Event

  • 禁止某些键盘事件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    document.addEventListener('keydown', function(event) {
    return (
    !(
    112 == event.keyCode || //F1
    123 == event.keyCode || //F12
    (event.ctrlKey && 82 == event.keyCode) || //ctrl + R
    (event.ctrlKey && 78 == event.keyCode) || //ctrl + N
    (event.shiftKey && 121 == event.keyCode) || //shift + F10
    (event.altKey && 115 == event.keyCode) || //alt + F4
    ('A' == event.srcElement.tagName && event.shiftKey)
    ) || (event.returnValue = false) //shift + 点击a标签
    )
    })
  • 禁止右键、选择、复制

    1
    2
    3
    4
    5
    ;['contextmenu', 'selectstart', 'copy'].forEach(function(eventName) {
    document.addEventListener(eventName, function(event) {
    return (event.returnValue = false)
    })
    })
  • transitionend

  • animationend

getComputedStyle

MDN - getComputedStyle

  • window.getComputedStyle 返回的 CSSStyleDeclaration 对象将包含所有受支持的 CSS 属性长名称的活动值。示例名称是 border-bottom-width,border-width 和 border 是示例速记属性名称。仅使用像 font-size 这样的名字来查询值是最安全的。 查询诸如 font 等简写名称不适用于大多数浏览器

  • CSS 属性值可以使用 getPropertyValue(propName) API 或直接索引到对象,如 cs['z-index']cs.zIndex

  • example

    1
    2
    3
    4
    5
    const elem1 = document.getElementById('elemId')
    const style = window.getComputedStyle(elem1, null)

    // 它等价于
    // const style = document.defaultView.getComputedStyle(elem1, null);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <style>
    #elem-container {
    position: absolute;
    left: 100px;
    top: 200px;
    height: 100px;
    }
    </style>

    <div id="elem-container">dummy</div>
    <div id="output"></div>

    <script>
    function getTheStyle() {
    const elem = document.getElementById('elem-container')
    const theCSSprop = window
    .getComputedStyle(elem, null)
    .getPropertyValue('height')
    document.getElementById('output').innerHTML = theCSSprop
    }
    getTheStyle()
    </script>

Animations

MDN - Web Animations API

GitHub polyfill

IntersectionObserver

MDN
阮一峰

Github polyfill

scrollIntoView

MDN - Element.scrollIntoView()

append

MDN - ParentNode.append()

  • 添加多个 node 节点或者 text 节点

  • Polyfill

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    ;(function(arr) {
    arr.forEach(function(item) {
    if (item.hasOwnProperty('append')) {
    return
    }
    Object.defineProperty(item, 'append', {
    configurable: true,
    enumerable: true,
    writable: true,
    value: function append() {
    var argArr = Array.prototype.slice.call(arguments),
    docFrag = document.createDocumentFragment()

    argArr.forEach(function(argItem) {
    var isNode = argItem instanceof Node
    docFrag.appendChild(
    isNode ? argItem : document.createTextNode(String(argItem))
    )
    })

    this.appendChild(docFrag)
    }
    })
    })
    })([Element.prototype, Document.prototype, DocumentFragment.prototype])

onWheel

兼容浏览器 wheel 事件

1
2
3
4
5
6
7
8
9
10
11
const onWheel = (function() {
const wheelEvt =
'onwheel' in document.createElement('div')
? 'wheel'
: document.onmousewheel !== undefined
? 'mousewheel'
: 'DOMMouseScroll'
return function(el, func) {
el.addEventListener(wheelEvt, func)
}
})()

MDN - Object

Table of Contents

Object.preventExtension

该方法将对象标记为不可扩展,阻止添加自身的属性,但不可扩展对象的属性仍然可被删除、修改,也可以添加到对象原型,尝试将新属性添加到不可扩展对象将静默失败或抛出 TypeError一旦使其不可扩展,就无法再对象进行扩展。

1
2
3
4
5
6
7
/**
* @description 方法让一个对象变的不可扩展,
* 也就是永远不能再添加新的属性
* @param {Object} 将要变得不可扩展的对象
* @return {Object} 已经不可扩展的对象
*/
Object.preventExtensions(obj)

Object.isExtensible

默认情况下,对象是可扩展的:即可以为他们添加新的属性。以及它们的 __proto__ 属性可以被更改。Object.preventExtensionsObject.sealObject.freeze 方法都可以标记一个对象为不可扩展(non-extensible)

1
2
3
4
5
6
7
/**
* @description 方法判断一个对象是否是可扩展的
* (是否可以在它上面添加新的属性)
* @param {Object} 需要检测的对象
* @return {Boolean} 表示给定对象是否可扩展
*/
Object.isExtensible(obj)

注:虽然 Object.freezeObject.seal 之后的对象是不可扩展的,但使用 Object.isExtensible 判断返回 false

Object.seal

密封一个对象,使对象不可扩展,且所有自身属性都不可配置、不可删除(但不一定是不可写)的对象

1
2
3
4
5
6
7
8
/**
* @description 封闭一个对象
* 阻止添加新属性并将所有现有属性标记为不可配置
* 当前属性的值只要可写就可以改变
* @param {Object} 将要被密封的对象
* @return {Object} 被密封的对象
*/
Object.seal(obj)
  1. 给对象设置,Object.preventExtension(obj)
    禁止更改原型,禁止添加属性

  2. 为对象的每一个属性设置,configurable:false
    禁止更改属性值

Object.freeze 不同的是,Object.seal 后的对象是可写的 writable:true,可以改变其现有属性

Object.isSealed

1
2
3
4
5
6
/**
* @description 方法判断一个对象是否被密封
* @param {Object} 被检测的对象
* @return {Boolean} 表示给定对象是否被密封
*/
Object.isSealed(obj)

Object.freeze

冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。

1
2
3
4
5
6
7
/**
* @description 被冻结对象自身的所有属性都不可能以任何方式被修改。
* 任何修改尝试都会失败,无论是静默地还是通过抛出TypeError异常
* @param {Object} 要被冻结的对象
* @return {Object} 被冻结的对象
*/
Object.freeze(obj)
  1. 给对象设置,Object.preventExtension(obj) 禁止更改原型,禁止添加属性

  2. 为对象的每一个属性设置,writable:false 禁止更改属性值

  3. 为对象的每一个属性设置,configurable:false 禁止删除属性

注:禁止添加属性,是 Object.preventExtensions 控制的,而禁止删除属性,是 configuable:false 控制的。用 Object.seal() 密封的对象可以改变它们现有的属性,使用 Object.freeze() 冻结的对象中现有属性是不可变的。

Object.isFrozen

一个对象是冻结的是指它不可扩展,所有属性都是不可配置的,且所有数据属性(即没有 gettersetter 组件的访问器的属性)都是不可写的。

1
2
3
4
5
6
/**
* @description 方法判断一个对象是否被冻结
* @param {Object} 被检测的对象
* @return {Boolean} 表示给定对象是否被冻结
*/
Object.isFrozen(obj)

Object.defineProperty

1
2
3
4
5
6
7
8
9
/**
* @description 方法会直接在一个对象上定义一个新属性
* 或者修改一个对象的现有属性,并返回这个对象
* @param {Object} obj 要在其上定义属性的对象
* @param {} prop 要定义或修改的属性的名称
* @param {} descriptor 将被定义或修改的属性描述符
* @return {Object} 被传递给函数的对象
*/
Object.defineProperty(obj, prop, descriptor)

descriptor

对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符数据描述符 是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符 是由 getter-setter 函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。

数据描述符和存取描述符均具有以下可选键值:

  • configurable

    当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false

  • enumerable

    当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false

数据描述符同时具有以下可选键值:

  • value

    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined

  • writable

    当且仅当该属性的 writable 为 true 时,value 才能被赋值运算符改变。默认为 false

存取描述符同时具有以下可选键值:

  • get

    一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入 this 对象(由于继承关系,这里的 this 并不一定是定义该属性的对象)

    默认为 undefined

  • set

    一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值

    默认为 undefined

keys

configurable enumerable value writable get set
数据描述符 Yes Yes Yes Yes No No
存取描述符 Yes Yes No No Yes Yes

如果一个描述符不具有 valuewritablegetset 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(valuewritable)和(getset)关键字,将会产生一个异常。

for…in

for...in 语句以任意顺序遍历一个对象的可枚举属性

for...in 也会遍历原型链上的可枚举属性,可以通过 Object.hasOwnProperty 方法判断是否自身属性

hasOwnProperty

所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性

1
2
3
const o = {}
'toString' in o // true
o.hasOwnProperty('toString') // false

防止方法被重写,使用 Object.prototype 上的方法定义一个工具函数

1
2
3
function hasOwn(target, key) {
return Object.prototype.hasOwnProperty.call(target, key)
}

注:和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性

Table of Contents

Initial

1
2
3
$ npm config set init.author.name xg4
$ npm config set init.author.email xingor4@gmail.com
$ npm config set init.license MIT

Publish

  • 登录 npm 账号

    1
    2
    3
    $ npm login
    # or
    $ npm adduser
  • 配置淘宝镜像之后,无法进行 publish

    1
    $ npm config set registry https://registry.npmjs.org
  • private package 需要进行 scope 的设置

    1
    $ npm config set scope <your_scope>

    scope 的包就成了@scope/xxx

  • 发布公有的 scope 包

    1
    $ npm publish --access=public
  • 撤销发布

    1
    $ npm unpublish --force

Release

使用 npm version <newVersion> 命令变更版本信息,自动 git tag

1
2
3
4
5
$ npm version <newVersion>
# ===
# bump package.json version
$ git commit -am "msg"
$ git tag "version"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
npm version [<newVersion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]

major:主版本号

minor:次版本号

patch:补丁号

premajor:预备主版本

preminor

prepatch:预备次版本

prerelease:预发布版本

若需要指定 commit 的信息,可以使用 -m 命令

1
2
3
npm version patch -m "build: release v%s"  # %s 会自动替换成版本号

# (tag: v0.0.1) build: release v0.0.1

需要注意的是,使用 npm version <newVersion> 命令,需要当前工作区为 clean 状态,否则会执行失败

Docker 入门教程 - 阮一峰

install

ubuntu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 更新包
$ sudo apt update

# 安装https支持包
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common

# 添加Docker官方GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 添加stable版的repository
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 更新apt
$ sudo apt update

# 安装最新的Docker CE
$ sudo apt install docker-ce

$ sudo systemctl status docker

更新/卸载

1
2
3
4
5
6
7
# 跟新
$ sudo apt upgrade

# 卸载Docker
$ sudo apt-get purge docker-ce
# 删除images、containers和volumes
$ sudo rm -rf /var/lib/docker

添加到用户组(可选项)

1
2
3
4
sudo groupadd docker
sudo usermod -aG docker $USER

sudo service docker restart

仓库镜像地址

1
2
3
4
--registry-mirror=https://jxus37ad.mirror.aliyuncs.com

sudo systemctl daemon-reload
sudo systemctl restart docker

docker-compose

docker compose install

1
2
3
4
5
6
7
8
# download
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# permissions
sudo chmod +x /usr/local/bin/docker-compose

# check
docker-compose --version

login / logout

登录/登出一个 Docker 镜像仓库,如果为指定镜像仓库地址,默认为官方仓库 Docker Hub

1
2
3
$ docker login [OPTIONS] [SERVER]

$ docker logout [OPTIONS] [SERVER]
  • OPTIONS :

    • -u : 登录的用户名

    • -p : 登录的密码

  • example

    1
    2
    3
    $ docker login -u xg4 -p xg4

    $ docker logout

image

Docker 官方提供的 image 文件,都在 library 组里,所以是默认组,可以省略。library/hello-world 为官方 image 仓库,可以省略 library

images

查看本地镜像

1
2
3
$ docker images [OPTIONS] [REPOSITORY[:TAG]]
# or
$ docker image ls
  • OPTIONS :

    • -a : 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层)

    • --digests : 显示镜像的摘要信息

    • -f : 显示满足条件的镜像

    • --format : 指定返回值的模板文件

    • --no-trunc : 显示完整的镜像信息

    • -q : 只显示镜像 ID

  • example

    1
    2
    3
    $ docker images

    $ docker images ubuntu

pull

从镜像仓库中拉取或者更新指定镜像

1
$ docker pull [OPTIONS] NAME[:TAG|@DIGEST]
  • OPTIONS :

    • -a : 拉取所有 tagged 镜像

    • --disable-content-trust : 忽略镜像的校验,默认开启

  • example

    1
    2
    3
    4
    5
    # 下载最新镜像
    $ docker pull ubuntu

    # 下载 repository 为 ubuntu 的所有镜像
    $ docker pull -a ubuntu

Docker Hub 中查找镜像

1
$ docker search [OPTIONS] imageName
  • OPTIONS :

    • --automated : 只列出 automated build 类型的镜像

    • --no-trunc : 显示完整的镜像描述

    • -s : 列出收藏数不小于指定值的镜像

  • 显示的信息 :

    • NAME : 镜像仓库源的名称

    • DESCRIPTION : 镜像的描述

    • OFFICIAL : 是否 docker 官方发布

build

使用 Dockerfile 创建镜像

1
$ docker build [OPTIONS] PATH | URL | -
  • OPTIONS :

    • --build-arg=[] : 设置镜像创建时的变量

    • --cpu-shares : 设置 cpu 使用权重

    • --cpu-period : 限制 CPU CFS 周期

    • --cpu-quota : 限制 CPU CFS 配额

    • --cpuset-cpus : 指定使用的 CPU id

    • --cpuset-mems : 指定使用的内存 id

    • --disable-content-trust : 忽略校验,默认开启

    • -f : 指定要使用的 Dockerfile 路径

    • --force-rm : 设置镜像过程中删除中间容器

    • --isolation : 使用容器隔离技术

    • --label=[] : 设置镜像使用的元数据

    • -m : 设置内存最大值

    • --memory-swap : 设置 Swap 的最大值为内存+swap,”-1”表示不限 swap

    • --no-cache : 创建镜像的过程不使用缓存

    • --pull : 尝试去更新镜像的新版本

    • --quiet, -q : 安静模式,成功后只输出镜像 ID

    • --rm : 设置镜像成功后删除中间容器

    • --shm-size : 设置/dev/shm 的大小,默认值是 64M

    • --ulimit : Ulimit 配置

    • --tag, -t : 指定要创建镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签,标签默认为 latest

    • --network : 默认 default。在构建期间设置 RUN 指令的网络模式

  • example

    1
    2
    3
    $ docker build -t <name> .
    # or 指定 image tag
    $ docker build -t <name>:<tag> .
    • . : Dockerfile 文件所在的路径,可以指定 Dockerfile 的绝对路径

rmi

删除本地一个或多个镜像

1
2
3
4
5
6
$ docker rmi [OPTIONS] IMAGE [IMAGE...]
# or
$ docker image rm [OPTIONS] IMAGE [IMAGE...]

# 删除本地所有镜像
$ docker rmi $(docker images -q)
  • OPTIONS :

    • -f : 强制删除

    • --no-prune : 不移除该镜像的过程镜像,默认移除

  • example

    1
    $ docker rmi -f ubuntu

tag

标记本地镜像,将其归入某一仓库

1
$ docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
  • example

    1
    $ docker tag ubuntu:12.0 xg4/ubuntu:v2

push

将本地的镜像上传到镜像仓库,要先登录到镜像仓库

1
$ docker push [OPTIONS] [USERNAME/]NAME[:TAG]
  • OPTIONS :

    • --disable-content-trust : 忽略镜像的校验,默认开启
  • example

    1
    $ docker push xg4/ubuntu:v2

save

将指定镜像保存成 tar 归档文件

1
$ docker save [OPTIONS] IMAGE [IMAGE...]
  • OPTIONS :

    • -o : 输出到的文件
  • example

    1
    $ docker save -o my_ubuntu_v2.tar xg4/ubuntu:v2

load

导入使用 docker save 命令导出的镜像

1
$ docker load [OPTIONS]
  • OPTIONS :

    • -i : 指定导出的文件

    • -q : 精简输出信息

  • example

    1
    2
    3
    # 导入镜像
    $ docker load -i ubuntu.tar
    $ docker load < ubuntu.tar

import

从归档文件 ( docker save ) 中创建镜像

1
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
  • OPTIONS :

    • -c : 应用 docker 指令创建镜像

    • -m : 提交时的说明文字

  • example

    1
    2
    3
    $ docker import my_ubuntu_v3.tar xg4/ubuntu:v4

    $ docker images xg4/ubuntu:v4

history

查看指定镜像的创建历史

1
$ docker history [OPTIONS] IMAGE
  • OPTIONS :

    • -H : 以可读的格式打印镜像大小和日期,默认为 true

    • --no-trunc : 显示完整的提交记录

    • -q : 仅列出提交记录 ID

  • example

    1
    $ docker history xg4/ubuntu:v3

container

ps

列出容器

1
2
3
$ docker ps [OPTIONS]
# or
$ docker container ls
  • OPTIONS :

    • -a : 显示所有的容器,包括未运行的

    • -f : 根据条件过滤显示的内容

    • --format : 指定返回值的模板文件

    • -l : 显示最近创建的容器

    • -n : 列出最近创建的 n 个容器

    • --no-trunc : 不截断输出

    • -q : 静默模式,只显示容器编号

    • -s : 显示总的文件大小

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 查看正在运行的容器
    $ docker container ls
    # or
    $ docker ps

    # 查看全部
    $ docker container ls -a
    # or
    $ docker ps -a

run/create

docker run - docs
run: 创建一个新的容器并运行一个命令。本地不存在镜像时,会先从远程仓库拉取,完成之后启动
create: 创建一个新的容器但不启动它,用法同 docker run

1
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  • OPTIONS :

    • -a stdin : 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项

    • -d : 后台运行容器,并返回容器 ID

    • -i : 以交互模式运行容器,通常与 -t 同时使用

    • -p : 端口映射,格式为:主机(宿主)端口:容器端口

    • -t : 为容器重新分配一个伪输入终端,通常与 -i 同时使用

    • --name="nginx-lb" : 为容器指定一个名称

    • --dns 8.8.8.8 : 指定容器使用的 DNS 服务器,默认和宿主一致

    • --dns-search example.com : 指定容器 DNS 搜索域名,默认和宿主一致

    • -h "mars" : 指定容器的 hostname

    • -e username="ritchie" : 设置环境变量

    • --env-file=[] : 从指定文件读入环境变量

    • --cpuset="0-2" or --cpuset="0,1,2" : 绑定容器到指定 CPU 运行

    • -m : 设置容器使用内存最大值

    • --net="bridge" : 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型

    • --link=[] : 添加链接到另一个容器

    • --expose=[] : 开放一个端口或一组端口

    • --rm : 退出时自动删除容器

    • --volume , -v : 卷映射,格式为:主机(宿主)卷:容器卷

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 使用镜像 ubuntu:latest,不指定 image:tag 时,默认为 latest
    $ docker run ubuntu

    # 后台模式启动一个容器,并将容器命名为 myUbuntu
    $ docker run --name myUbuntu -d ubuntu:latest

    # 以交互模式启动一个容器,在容器内执行/bin/bash命令,容器的 Shell 映射到当前的 Shell
    $ docker run -it ubuntu /bin/bash

    # 容器的 3000 端口映射到本机的 8000 端口
    $ docker run -p 8000:3000 ubuntu

    # 绑定容器的 8080 端口,并将其映射到本地主机 127.0.0.1 的 80 端口上
    $ docker run -p 127.0.0.1:80:8080/tcp ubuntu bash

    # 主机的目录 /data 映射到容器的 /data
    $ docker run -v /data:/data ubuntu

start/stop/restart

start: 启动一个或多个已经被停止的容器
stop: 停止一个运行中的容器
restart: 重启容器

1
2
3
4
5
6
7
8
$ docker start [OPTIONS] CONTAINER [CONTAINER...]

$ docker stop [OPTIONS] CONTAINER [CONTAINER...]

# 停止全部容器
$ docker stop $(docker ps -aq)

$ docker restart [OPTIONS] CONTAINER [CONTAINER...]
  • example

    1
    2
    3
    4
    5
    6
    7
    8
    # 启动已被停止的容器
    $ docker start a2erd232d

    # 停止运行中的容器 myUbuntu
    $ docker stop myUbuntu

    # 重启容器
    $ docker restart a2erd232d

kill

杀掉一个运行中的容器。依然会占据硬盘空间

1
2
3
4
$ docker kill [OPTIONS] CONTAINER [CONTAINER...]

# 杀掉全部容器
$ docker kill $(docker ps -aq)
  • OPTIONS :

    • -s : 向容器发送一个信号
  • example

    1
    $ docker kill -s KILL_YOU myUbuntu

kill 会立即结束,stop 进行收尾清理工作,再结束

rm

删除一个或多少容器

1
2
3
4
$ docker rm [OPTIONS] CONTAINER [CONTAINER...]

# 删除全部容器
$ docker rm $(docker ps -aq)
  • OPTIONS :

    • -f : 通过 SIGKILL 信号强制删除一个运行中的容器

    • -l : 移除容器间的网络连接,而非容器本身

    • -v : -v 删除与容器关联的卷

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    # 强制删除容器db01、db02
    $ docker rm -f db01 db02

    # 移除容器nginx01对容器db01的连接,连接名db
    $ docker rm -l db

    # 删除容器nginx01,并删除容器挂载的数据卷
    $ docker rm -v nginx01

exec

在运行的容器中执行命令

1
$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
  • OPTIONS :

    • -d : 分离模式: 在后台运行

    • -i : 即使没有附加也保持 STDIN 打开

    • -t : 分配一个伪终端

  • example

    1
    2
    3
    4
    5
    # 在容器 9df70f 中以交互模式执行容器内 /root/shell.sh 脚本
    $ docker exec -it 9df70f /bin/sh /root/shell.sh

    # 在容器 myUbuntu 中开启一个交互模式的终端
    $ docker exec -it myUbuntu /bin/bash

pause/unpause

pause : 暂停容器中所有的进程
unpause : 恢复容器中所有的进程

1
2
$ docker pause [OPTIONS] CONTAINER [CONTAINER...]
$ docker unpause [OPTIONS] CONTAINER [CONTAINER...]
  • example

    1
    2
    3
    4
    5
    # 暂停数据库容器 db01 提供服务
    $ docker pause db01

    # 恢复数据库容器 db01 提供服务
    $ docker unpause db01

logs

获取容器的日志

1
$ docker logs [OPTIONS] CONTAINER
  • OPTIONS :

    • -f : 跟踪日志输出

    • --since : 显示某个开始时间的所有日志

    • -t : 显示时间戳

    • --tail : 仅列出最新 N 条容器日志

  • example

    1
    2
    3
    4
    5
    # 跟踪查看容器 myUbuntu 的日志输出
    $ docker logs -f myUbuntu

    # 查看容器 myUbuntu 从2019年4月1日后的最新10条日志
    $ docker logs --since="2019-04-01" --tail=10 myUbuntu

inspect

获取容器/镜像的元数据

1
$ docker inspect [OPTIONS] NAME|ID [NAME|ID...]
  • OPTIONS :

    • -f : 指定返回值的模板文件

    • -s : 显示总的文件大小

    • --type : 为指定类型返回 JSON

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 获取镜像 ubuntu:latest 的元信息
    $ docker inspect ubuntu:latest
    [
    {
    "Id": "sha256:ae9a045f866bbc2553087f6e42bfc16074a74f"
    ...

    # 获取正在运行的容器 myUbuntu 的 IP
    $ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myUbuntu
    172.17.0.3

port

列出指定的容器的端口映射,或者查找将 PRIVATE_PORT NAT 到面向公众的端口

1
$ docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]
  • example

    1
    2
    $ docker port myUbuntu
    3000/tcp -> 0.0.0.0:3000

export

将文件系统作为一个 tar 归档文件导出到 STDOUT

1
$ docker export [OPTIONS] CONTAINER
  • OPTIONS :

    • -o : 将输入内容写到文件
  • example

    1
    2
    3
    4
    # 将 id 为 66bbc25530 的容器按日期保存为 tar 文件
    $ docker export -o logs-`date +%Y%m%d`.tar 66bbc25530
    $ ls logs-`date +%Y%m%d`.tar
    logs-20190411.tar

cp

用于容器与主机之间的数据拷贝

1
2
3
$ docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

$ docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
  • OPTIONS :

    • -L : 保持源目标中的链接
  • example

    1
    2
    3
    4
    5
    6
    7
    8
    # 将主机 ~/Desktop/data 目录拷贝到容器 2ae6iu3w 的 /data 目录下
    $ docker cp ~/Desktop/data 2ae6iu3w:/data/

    # 将主机 ~/Desktop/data 目录拷贝到容器 2ae6iu3w 中,目录重命名为 data
    $ docker cp ~/Desktop/data 2ae6iu3w:/data

    # 将容器 2ae6iu3w 的 /data 目录拷贝到主机的当前目录中
    $ docker cp 96f7f14e99ab:/data .

commit

从容器创建一个新的镜像

1
$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
  • OPTIONS :

    • -a : 提交的镜像作者

    • -c : 使用 Dockerfile 指令来创建镜像

    • -m : 提交时的说明文字

    • -p : 在 commit 时,将容器暂停

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    $ docker run -it ubuntu /bin/bash
    # in container
    $ root@e18edb10161:/# apt update
    $ root@e18edb10161:/# exit

    # 将容器 e18edb10161 保存为新的镜像,添加提交人信息和说明信息,指定目标镜像的名字和版本号为 ubuntu:v2
    $ docker commit -m='update' -a='xg4' e18edb10161 ubuntu:v2
    $ sha256:70bf1840fd7c0d2d8ef0a42a817eb29f854c1af8f7c59fc03ac7bdee9545aff8

diff

检查容器里文件结构的更改

1
$ docker diff [OPTIONS] CONTAINER
  • example

    1
    2
    3
    4
    5
    $ docker diff myUbuntu
    A /logs
    A /xg4
    A /var/www/index.html
    C /tmp

Table of Contents

a

rel

  • 赞助商链接

    1
    <a rel="sponsored"></a>
  • 用户提供的链接

    1
    <a rel="ugc"></a>
  • 完全忽略该链接

    1
    <a rel="nofollow"></a>

html

MDN - html

ruby

MDN - ruby
被用来展示东亚文字注音或字符注释

example

1
2
3
4
5
<ruby>
<rp>(</rp><rt>han</rt><rp>)</rp><rp>(</rp><rt>zi</rt><rp>)</rp>
</ruby>

<ruby> 明 日 <rp>(</rp><rt>ming ri</rt><rp>)</rp> </ruby>

figure

MDN - figure
代表一段独立的内容,在主文中引用的图片,插图,表格,代码段, 和 figcaption 一起使用,figcaption 表示说明文字或者标题,当这部分转移到附录中或者其他页面时不会影响到主体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- only figure -->
<figure>
<img src="source" alt="img" />
</figure>

<!-- image -->
<figure>
<img src="source" alt="img" />
<figcaption>An image</figcaption>
</figure>

<!-- code -->
<figure>
<figcaption>Get browser details using <code>navigator</code>.</figcaption>
<pre>
function NavigatorExample() {
var txt;
txt = "Browser CodeName: " + navigator.appCodeName + "; ";
txt+= "Browser Name: " + navigator.appName + "; ";
txt+= "Browser Version: " + navigator.appVersion + "; ";
txt+= "Cookies Enabled: " + navigator.cookieEnabled + "; ";
txt+= "Platform: " + navigator.platform + "; ";
txt+= "User-agent header: " + navigator.userAgent + "; ";
console.log("NavigatorExample", txt);
}
</pre>
</figure>

<!-- reference -->
<figure>
<figcaption><cite>Edsger Dijkstra:</cite></figcaption>
<blockquote>
If debugging is the process of removing software bugs, then programming must
be the process of putting them in.
</blockquote>
</figure>

<!-- text -->
<figure>
<p style="white-space:pre">
Bid me discourse, I will enchant thine ear, Or like a fairy trip upon the
green, Or, like a nymph, with long dishevell'd hair, Dance on the sands, and
yet no footing seen: Love is a spirit all compact of fire, Not gross to
sink, but light, and will aspire.
</p>
<figcaption><cite>Venus and Adonis</cite>, by William Shakespeare</figcaption>
</figure>

HTML5 结构化元素

标签 作用
header body、main 标签的直接子标签,位置在页面头部,内容可能为 logo、标语、搜索提示、导航栏
nav 导航栏包在 nav 标签内,可能出现在头部、侧边栏、底部等等,神奇的地方在于设置 nav 标签的 display:inline-block,是作用在 li 标签上的
main body 标签的直接子标签,主内容区域
aside 侧边栏
article 一般出现在 main 标签内,article 标签内可以有 section、footer 等标签,是比较独立的内容,比如像博客网站主页的一个文章简介
section section 和 div 很类似,如果使用 div 标签是为了对内容做样式控制,或者为了便于 javascript 获取做其他操作,那么使用 div 就是你的答案,其他情况就用 section
address 提供联系信息,放在 article 标签内提供文章作者信息,放在 main、body、footer 内提供网站信息
footer 一般在 HTML 结构底部,补充网站信息,如果放在 article 内补充文章信息

Meta

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<meta charset="utf-8" />

<!-- SEO -->
<title>document</title>
<meta name="keywords" content="keywords" />
<meta name="description" content="description" />

<meta name="author" content="xg4, xingor4@gmail.com" />

<!-- mobile -->
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, shrink-to-fit=no"
/>

<meta name="theme-color" content="#000000" />

<!-- chromium -->
<meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1" />
<meta name="renderer" content="webkit|ie-comp|ie-stand" />
<meta name="force-rendering" content="webkit|ie-comp|ie-stand" />

<!-- full screen -->
<meta name="full-screen" content="yes" />
<meta name="x5-fullscreen" content="true" />

<!-- robots -->
<meta name="robots" content="index, about" />

<!-- orientation -->
<meta name="screen-orientation" content="portrait" />
<meta name="x5-orientation" content="portrait" />

<!-- 禁止识别电话号码和邮箱 -->
<meta name="format-detection" content="telephone=no, email=no" />

<!-- web app -->
<meta name="browsermode" content="application" />
<meta name="x5-page-mode" content="app" />
<meta name="apple-mobile-web-app-capable" content="yes" />

<!-- status bar style -->
<meta name="apple-mobile-web-app-status-bar-style" content="default" />

<!-- add to home screen of title -->
<meta name="apple-mobile-web-app-title" content="title" />

<!-- windows phone tap highlight -->
<meta name="msapplication-tap-highlight" content="no" />

<!-- old device -->
<meta name="MobileOptimized" content="320" />
<meta name="HandheldFriendly" content="true" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- icon -->
<link
rel="apple-touch-icon-precomposed"
sizes="57x57"
href="/icons/apple-touch-icon.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="72x72"
href="/icons/apple-touch-icon.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="114x114"
href="/icons/apple-touch-icon.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="144x144"
href="/icons/apple-touch-icon.png"
/>

<!-- PWA -->
<link rel="manifest" href="/manifest.json" />

<!-- favicon -->
<link rel="shortcut icon" href="/favicon.ico" />

Table of Contents

Kit

知乎

V2EX